compiler-sfc.cjs.js 95 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var CompilerDOM = require('@vue/compiler-dom');
  4. var sourceMap = require('source-map');
  5. var hash = require('hash-sum');
  6. var path = require('path');
  7. var compilerCore = require('@vue/compiler-core');
  8. var url = require('url');
  9. var shared = require('@vue/shared');
  10. var CompilerSSR = require('@vue/compiler-ssr');
  11. var postcss = require('postcss');
  12. var selectorParser = require('postcss-selector-parser');
  13. var merge = require('merge-source-map');
  14. var MagicString = require('magic-string');
  15. var parser = require('@babel/parser');
  16. var estreeWalker = require('estree-walker');
  17. function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e['default'] : e; }
  18. function _interopNamespace(e) {
  19. if (e && e.__esModule) return e;
  20. var n = Object.create(null);
  21. if (e) {
  22. Object.keys(e).forEach(function (k) {
  23. n[k] = e[k];
  24. });
  25. }
  26. n['default'] = e;
  27. return Object.freeze(n);
  28. }
  29. var CompilerDOM__namespace = /*#__PURE__*/_interopNamespace(CompilerDOM);
  30. var hash__default = /*#__PURE__*/_interopDefaultLegacy(hash);
  31. var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
  32. var CompilerSSR__namespace = /*#__PURE__*/_interopNamespace(CompilerSSR);
  33. var postcss__default = /*#__PURE__*/_interopDefaultLegacy(postcss);
  34. var selectorParser__default = /*#__PURE__*/_interopDefaultLegacy(selectorParser);
  35. var merge__default = /*#__PURE__*/_interopDefaultLegacy(merge);
  36. var MagicString__default = /*#__PURE__*/_interopDefaultLegacy(MagicString);
  37. const CSS_VARS_HELPER = `useCssVars`;
  38. const cssVarRE = /\bv-bind\(\s*(?:'([^']+)'|"([^"]+)"|([^'"][^)]*))\s*\)/g;
  39. function genCssVarsFromList(vars, id, isProd) {
  40. return `{\n ${vars
  41. .map(key => `"${genVarName(id, key, isProd)}": (${key})`)
  42. .join(',\n ')}\n}`;
  43. }
  44. function genVarName(id, raw, isProd) {
  45. if (isProd) {
  46. return hash__default(id + raw);
  47. }
  48. else {
  49. return `${id}-${raw.replace(/([^\w-])/g, '_')}`;
  50. }
  51. }
  52. function parseCssVars(sfc) {
  53. const vars = [];
  54. sfc.styles.forEach(style => {
  55. let match;
  56. while ((match = cssVarRE.exec(style.content))) {
  57. vars.push(match[1] || match[2] || match[3]);
  58. }
  59. });
  60. return vars;
  61. }
  62. const cssVarsPlugin = opts => {
  63. const { id, isProd } = opts;
  64. return {
  65. postcssPlugin: 'vue-sfc-vars',
  66. Declaration(decl) {
  67. // rewrite CSS variables
  68. if (cssVarRE.test(decl.value)) {
  69. decl.value = decl.value.replace(cssVarRE, (_, $1, $2, $3) => {
  70. return `var(--${genVarName(id, $1 || $2 || $3, isProd)})`;
  71. });
  72. }
  73. }
  74. };
  75. };
  76. cssVarsPlugin.postcss = true;
  77. function genCssVarsCode(vars, bindings, id, isProd) {
  78. const varsExp = genCssVarsFromList(vars, id, isProd);
  79. const exp = CompilerDOM.createSimpleExpression(varsExp, false);
  80. const context = CompilerDOM.createTransformContext(CompilerDOM.createRoot([]), {
  81. prefixIdentifiers: true,
  82. inline: true,
  83. bindingMetadata: bindings
  84. });
  85. const transformed = CompilerDOM.processExpression(exp, context);
  86. const transformedString = transformed.type === 4 /* SIMPLE_EXPRESSION */
  87. ? transformed.content
  88. : transformed.children
  89. .map(c => {
  90. return typeof c === 'string'
  91. ? c
  92. : c.content;
  93. })
  94. .join('');
  95. return `_${CSS_VARS_HELPER}(_ctx => (${transformedString}))`;
  96. }
  97. // <script setup> already gets the calls injected as part of the transform
  98. // this is only for single normal <script>
  99. function genNormalScriptCssVarsCode(cssVars, bindings, id, isProd) {
  100. return (`\nimport { ${CSS_VARS_HELPER} as _${CSS_VARS_HELPER} } from 'vue'\n` +
  101. `const __injectCSSVars__ = () => {\n${genCssVarsCode(cssVars, bindings, id, isProd)}}\n` +
  102. `const __setup__ = __default__.setup\n` +
  103. `__default__.setup = __setup__\n` +
  104. ` ? (props, ctx) => { __injectCSSVars__();return __setup__(props, ctx) }\n` +
  105. ` : __injectCSSVars__\n`);
  106. }
  107. const hasWarned = {};
  108. function warnOnce(msg) {
  109. const isNodeProd = typeof process !== 'undefined' && process.env.NODE_ENV === 'production';
  110. if (!isNodeProd && !false && !hasWarned[msg]) {
  111. hasWarned[msg] = true;
  112. warn(msg);
  113. }
  114. }
  115. function warn(msg) {
  116. console.warn(`\x1b[1m\x1b[33m[@vue/compiler-sfc]\x1b[0m\x1b[33m ${msg}\x1b[0m\n`);
  117. }
  118. function warnExperimental(feature, rfcId) {
  119. warnOnce(`${feature} is still an experimental proposal.\n` +
  120. `Follow its status at https://github.com/vuejs/rfcs/pull/${rfcId}.`);
  121. warnOnce(`When using experimental features,\n` +
  122. `it is recommended to pin your vue dependencies to exact versions to avoid breakage.`);
  123. }
  124. const SFC_CACHE_MAX_SIZE = 500;
  125. const sourceToSFC = new (require('lru-cache'))(SFC_CACHE_MAX_SIZE);
  126. function parse(source, { sourceMap = true, filename = 'anonymous.vue', sourceRoot = '', pad = false, compiler = CompilerDOM__namespace } = {}) {
  127. const sourceKey = source + sourceMap + filename + sourceRoot + pad + compiler.parse;
  128. const cache = sourceToSFC.get(sourceKey);
  129. if (cache) {
  130. return cache;
  131. }
  132. const descriptor = {
  133. filename,
  134. source,
  135. template: null,
  136. script: null,
  137. scriptSetup: null,
  138. styles: [],
  139. customBlocks: [],
  140. cssVars: []
  141. };
  142. const errors = [];
  143. const ast = compiler.parse(source, {
  144. // there are no components at SFC parsing level
  145. isNativeTag: () => true,
  146. // preserve all whitespaces
  147. isPreTag: () => true,
  148. getTextMode: ({ tag, props }, parent) => {
  149. // all top level elements except <template> are parsed as raw text
  150. // containers
  151. if ((!parent && tag !== 'template') ||
  152. // <template lang="xxx"> should also be treated as raw text
  153. (tag === 'template' &&
  154. props.some(p => p.type === 6 /* ATTRIBUTE */ &&
  155. p.name === 'lang' &&
  156. p.value &&
  157. p.value.content &&
  158. p.value.content !== 'html'))) {
  159. return 2 /* RAWTEXT */;
  160. }
  161. else {
  162. return 0 /* DATA */;
  163. }
  164. },
  165. onError: e => {
  166. errors.push(e);
  167. }
  168. });
  169. ast.children.forEach(node => {
  170. if (node.type !== 1 /* ELEMENT */) {
  171. return;
  172. }
  173. if (!node.children.length && !hasSrc(node) && node.tag !== 'template') {
  174. return;
  175. }
  176. switch (node.tag) {
  177. case 'template':
  178. if (!descriptor.template) {
  179. const templateBlock = (descriptor.template = createBlock(node, source, false));
  180. templateBlock.ast = node;
  181. }
  182. else {
  183. errors.push(createDuplicateBlockError(node));
  184. }
  185. break;
  186. case 'script':
  187. const scriptBlock = createBlock(node, source, pad);
  188. const isSetup = !!scriptBlock.attrs.setup;
  189. if (isSetup && !descriptor.scriptSetup) {
  190. descriptor.scriptSetup = scriptBlock;
  191. break;
  192. }
  193. if (!isSetup && !descriptor.script) {
  194. descriptor.script = scriptBlock;
  195. break;
  196. }
  197. errors.push(createDuplicateBlockError(node, isSetup));
  198. break;
  199. case 'style':
  200. const styleBlock = createBlock(node, source, pad);
  201. if (styleBlock.attrs.vars) {
  202. errors.push(new SyntaxError(`<style vars> has been replaced by a new proposal: ` +
  203. `https://github.com/vuejs/rfcs/pull/231`));
  204. }
  205. descriptor.styles.push(styleBlock);
  206. break;
  207. default:
  208. descriptor.customBlocks.push(createBlock(node, source, pad));
  209. break;
  210. }
  211. });
  212. if (descriptor.scriptSetup) {
  213. if (descriptor.scriptSetup.src) {
  214. errors.push(new SyntaxError(`<script setup> cannot use the "src" attribute because ` +
  215. `its syntax will be ambiguous outside of the component.`));
  216. descriptor.scriptSetup = null;
  217. }
  218. if (descriptor.script && descriptor.script.src) {
  219. errors.push(new SyntaxError(`<script> cannot use the "src" attribute when <script setup> is ` +
  220. `also present because they must be processed together.`));
  221. descriptor.script = null;
  222. }
  223. }
  224. if (sourceMap) {
  225. const genMap = (block) => {
  226. if (block && !block.src) {
  227. block.map = generateSourceMap(filename, source, block.content, sourceRoot, !pad || block.type === 'template' ? block.loc.start.line - 1 : 0);
  228. }
  229. };
  230. genMap(descriptor.template);
  231. genMap(descriptor.script);
  232. descriptor.styles.forEach(genMap);
  233. descriptor.customBlocks.forEach(genMap);
  234. }
  235. // parse CSS vars
  236. descriptor.cssVars = parseCssVars(descriptor);
  237. if (descriptor.cssVars.length) {
  238. warnExperimental(`v-bind() CSS variable injection`, 231);
  239. }
  240. const result = {
  241. descriptor,
  242. errors
  243. };
  244. sourceToSFC.set(sourceKey, result);
  245. return result;
  246. }
  247. function createDuplicateBlockError(node, isScriptSetup = false) {
  248. const err = new SyntaxError(`Single file component can contain only one <${node.tag}${isScriptSetup ? ` setup` : ``}> element`);
  249. err.loc = node.loc;
  250. return err;
  251. }
  252. function createBlock(node, source, pad) {
  253. const type = node.tag;
  254. let { start, end } = node.loc;
  255. let content = '';
  256. if (node.children.length) {
  257. start = node.children[0].loc.start;
  258. end = node.children[node.children.length - 1].loc.end;
  259. content = source.slice(start.offset, end.offset);
  260. }
  261. const loc = {
  262. source: content,
  263. start,
  264. end
  265. };
  266. const attrs = {};
  267. const block = {
  268. type,
  269. content,
  270. loc,
  271. attrs
  272. };
  273. if (pad) {
  274. block.content = padContent(source, block, pad) + block.content;
  275. }
  276. node.props.forEach(p => {
  277. if (p.type === 6 /* ATTRIBUTE */) {
  278. attrs[p.name] = p.value ? p.value.content || true : true;
  279. if (p.name === 'lang') {
  280. block.lang = p.value && p.value.content;
  281. }
  282. else if (p.name === 'src') {
  283. block.src = p.value && p.value.content;
  284. }
  285. else if (type === 'style') {
  286. if (p.name === 'scoped') {
  287. block.scoped = true;
  288. }
  289. else if (p.name === 'module') {
  290. block.module = attrs[p.name];
  291. }
  292. }
  293. else if (type === 'script' && p.name === 'setup') {
  294. block.setup = attrs.setup;
  295. }
  296. }
  297. });
  298. return block;
  299. }
  300. const splitRE = /\r?\n/g;
  301. const emptyRE = /^(?:\/\/)?\s*$/;
  302. const replaceRE = /./g;
  303. function generateSourceMap(filename, source, generated, sourceRoot, lineOffset) {
  304. const map = new sourceMap.SourceMapGenerator({
  305. file: filename.replace(/\\/g, '/'),
  306. sourceRoot: sourceRoot.replace(/\\/g, '/')
  307. });
  308. map.setSourceContent(filename, source);
  309. generated.split(splitRE).forEach((line, index) => {
  310. if (!emptyRE.test(line)) {
  311. const originalLine = index + 1 + lineOffset;
  312. const generatedLine = index + 1;
  313. for (let i = 0; i < line.length; i++) {
  314. if (!/\s/.test(line[i])) {
  315. map.addMapping({
  316. source: filename,
  317. original: {
  318. line: originalLine,
  319. column: i
  320. },
  321. generated: {
  322. line: generatedLine,
  323. column: i
  324. }
  325. });
  326. }
  327. }
  328. }
  329. });
  330. return JSON.parse(map.toString());
  331. }
  332. function padContent(content, block, pad) {
  333. content = content.slice(0, block.loc.start.offset);
  334. if (pad === 'space') {
  335. return content.replace(replaceRE, ' ');
  336. }
  337. else {
  338. const offset = content.split(splitRE).length;
  339. const padChar = block.type === 'script' && !block.lang ? '//\n' : '\n';
  340. return Array(offset).join(padChar);
  341. }
  342. }
  343. function hasSrc(node) {
  344. return node.props.some(p => {
  345. if (p.type !== 6 /* ATTRIBUTE */) {
  346. return false;
  347. }
  348. return p.name === 'src';
  349. });
  350. }
  351. function isRelativeUrl(url) {
  352. const firstChar = url.charAt(0);
  353. return firstChar === '.' || firstChar === '~' || firstChar === '@';
  354. }
  355. const externalRE = /^https?:\/\//;
  356. function isExternalUrl(url) {
  357. return externalRE.test(url);
  358. }
  359. const dataUrlRE = /^\s*data:/i;
  360. function isDataUrl(url) {
  361. return dataUrlRE.test(url);
  362. }
  363. /**
  364. * Parses string url into URL object.
  365. */
  366. function parseUrl(url) {
  367. const firstChar = url.charAt(0);
  368. if (firstChar === '~') {
  369. const secondChar = url.charAt(1);
  370. url = url.slice(secondChar === '/' ? 2 : 1);
  371. }
  372. return parseUriParts(url);
  373. }
  374. /**
  375. * vuejs/component-compiler-utils#22 Support uri fragment in transformed require
  376. * @param urlString an url as a string
  377. */
  378. function parseUriParts(urlString) {
  379. // A TypeError is thrown if urlString is not a string
  380. // @see https://nodejs.org/api/url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost
  381. return url.parse(shared.isString(urlString) ? urlString : '', false, true);
  382. }
  383. const defaultAssetUrlOptions = {
  384. base: null,
  385. includeAbsolute: false,
  386. tags: {
  387. video: ['src', 'poster'],
  388. source: ['src'],
  389. img: ['src'],
  390. image: ['xlink:href', 'href'],
  391. use: ['xlink:href', 'href']
  392. }
  393. };
  394. const normalizeOptions = (options) => {
  395. if (Object.keys(options).some(key => shared.isArray(options[key]))) {
  396. // legacy option format which directly passes in tags config
  397. return {
  398. ...defaultAssetUrlOptions,
  399. tags: options
  400. };
  401. }
  402. return {
  403. ...defaultAssetUrlOptions,
  404. ...options
  405. };
  406. };
  407. const createAssetUrlTransformWithOptions = (options) => {
  408. return (node, context) => transformAssetUrl(node, context, options);
  409. };
  410. /**
  411. * A `@vue/compiler-core` plugin that transforms relative asset urls into
  412. * either imports or absolute urls.
  413. *
  414. * ``` js
  415. * // Before
  416. * createVNode('img', { src: './logo.png' })
  417. *
  418. * // After
  419. * import _imports_0 from './logo.png'
  420. * createVNode('img', { src: _imports_0 })
  421. * ```
  422. */
  423. const transformAssetUrl = (node, context, options = defaultAssetUrlOptions) => {
  424. if (node.type === 1 /* ELEMENT */) {
  425. if (!node.props.length) {
  426. return;
  427. }
  428. const tags = options.tags || defaultAssetUrlOptions.tags;
  429. const attrs = tags[node.tag];
  430. const wildCardAttrs = tags['*'];
  431. if (!attrs && !wildCardAttrs) {
  432. return;
  433. }
  434. const assetAttrs = (attrs || []).concat(wildCardAttrs || []);
  435. node.props.forEach((attr, index) => {
  436. if (attr.type !== 6 /* ATTRIBUTE */ ||
  437. !assetAttrs.includes(attr.name) ||
  438. !attr.value ||
  439. isExternalUrl(attr.value.content) ||
  440. isDataUrl(attr.value.content) ||
  441. attr.value.content[0] === '#' ||
  442. (!options.includeAbsolute && !isRelativeUrl(attr.value.content))) {
  443. return;
  444. }
  445. const url = parseUrl(attr.value.content);
  446. if (options.base && attr.value.content[0] === '.') {
  447. // explicit base - directly rewrite relative urls into absolute url
  448. // to avoid generating extra imports
  449. // Allow for full hostnames provided in options.base
  450. const base = parseUrl(options.base);
  451. const protocol = base.protocol || '';
  452. const host = base.host ? protocol + '//' + base.host : '';
  453. const basePath = base.path || '/';
  454. // when packaged in the browser, path will be using the posix-
  455. // only version provided by rollup-plugin-node-builtins.
  456. attr.value.content =
  457. host +
  458. (path__default.posix || path__default).join(basePath, url.path + (url.hash || ''));
  459. return;
  460. }
  461. // otherwise, transform the url into an import.
  462. // this assumes a bundler will resolve the import into the correct
  463. // absolute url (e.g. webpack file-loader)
  464. const exp = getImportsExpressionExp(url.path, url.hash, attr.loc, context);
  465. node.props[index] = {
  466. type: 7 /* DIRECTIVE */,
  467. name: 'bind',
  468. arg: compilerCore.createSimpleExpression(attr.name, true, attr.loc),
  469. exp,
  470. modifiers: [],
  471. loc: attr.loc
  472. };
  473. });
  474. }
  475. };
  476. function getImportsExpressionExp(path, hash, loc, context) {
  477. if (path) {
  478. const existing = context.imports.find(i => i.path === path);
  479. if (existing) {
  480. return existing.exp;
  481. }
  482. const name = `_imports_${context.imports.length}`;
  483. const exp = compilerCore.createSimpleExpression(name, false, loc, 2 /* CAN_HOIST */);
  484. context.imports.push({ exp, path });
  485. if (hash && path) {
  486. return context.hoist(compilerCore.createSimpleExpression(`${name} + '${hash}'`, false, loc, 2 /* CAN_HOIST */));
  487. }
  488. else {
  489. return exp;
  490. }
  491. }
  492. else {
  493. return compilerCore.createSimpleExpression(`''`, false, loc, 2 /* CAN_HOIST */);
  494. }
  495. }
  496. const srcsetTags = ['img', 'source'];
  497. // http://w3c.github.io/html/semantics-embedded-content.html#ref-for-image-candidate-string-5
  498. const escapedSpaceCharacters = /( |\\t|\\n|\\f|\\r)+/g;
  499. const createSrcsetTransformWithOptions = (options) => {
  500. return (node, context) => transformSrcset(node, context, options);
  501. };
  502. const transformSrcset = (node, context, options = defaultAssetUrlOptions) => {
  503. if (node.type === 1 /* ELEMENT */) {
  504. if (srcsetTags.includes(node.tag) && node.props.length) {
  505. node.props.forEach((attr, index) => {
  506. if (attr.name === 'srcset' && attr.type === 6 /* ATTRIBUTE */) {
  507. if (!attr.value)
  508. return;
  509. const value = attr.value.content;
  510. if (!value)
  511. return;
  512. const imageCandidates = value.split(',').map(s => {
  513. // The attribute value arrives here with all whitespace, except
  514. // normal spaces, represented by escape sequences
  515. const [url, descriptor] = s
  516. .replace(escapedSpaceCharacters, ' ')
  517. .trim()
  518. .split(' ', 2);
  519. return { url, descriptor };
  520. });
  521. // for data url need recheck url
  522. for (let i = 0; i < imageCandidates.length; i++) {
  523. if (imageCandidates[i].url.trim().startsWith('data:')) {
  524. imageCandidates[i + 1].url =
  525. imageCandidates[i].url + ',' + imageCandidates[i + 1].url;
  526. imageCandidates.splice(i, 1);
  527. }
  528. }
  529. // When srcset does not contain any relative URLs, skip transforming
  530. if (!options.includeAbsolute &&
  531. !imageCandidates.some(({ url }) => isRelativeUrl(url))) {
  532. return;
  533. }
  534. if (options.base) {
  535. const base = options.base;
  536. const set = [];
  537. imageCandidates.forEach(({ url, descriptor }) => {
  538. descriptor = descriptor ? ` ${descriptor}` : ``;
  539. if (isRelativeUrl(url)) {
  540. set.push((path__default.posix || path__default).join(base, url) + descriptor);
  541. }
  542. else {
  543. set.push(url + descriptor);
  544. }
  545. });
  546. attr.value.content = set.join(', ');
  547. return;
  548. }
  549. const compoundExpression = compilerCore.createCompoundExpression([], attr.loc);
  550. imageCandidates.forEach(({ url, descriptor }, index) => {
  551. if (!isExternalUrl(url) &&
  552. !isDataUrl(url) &&
  553. (options.includeAbsolute || isRelativeUrl(url))) {
  554. const { path } = parseUrl(url);
  555. let exp;
  556. if (path) {
  557. const existingImportsIndex = context.imports.findIndex(i => i.path === path);
  558. if (existingImportsIndex > -1) {
  559. exp = compilerCore.createSimpleExpression(`_imports_${existingImportsIndex}`, false, attr.loc, 2 /* CAN_HOIST */);
  560. }
  561. else {
  562. exp = compilerCore.createSimpleExpression(`_imports_${context.imports.length}`, false, attr.loc, 2 /* CAN_HOIST */);
  563. context.imports.push({ exp, path });
  564. }
  565. compoundExpression.children.push(exp);
  566. }
  567. }
  568. else {
  569. const exp = compilerCore.createSimpleExpression(`"${url}"`, false, attr.loc, 2 /* CAN_HOIST */);
  570. compoundExpression.children.push(exp);
  571. }
  572. const isNotLast = imageCandidates.length - 1 > index;
  573. if (descriptor && isNotLast) {
  574. compoundExpression.children.push(` + '${descriptor}, ' + `);
  575. }
  576. else if (descriptor) {
  577. compoundExpression.children.push(` + '${descriptor}'`);
  578. }
  579. else if (isNotLast) {
  580. compoundExpression.children.push(` + ', ' + `);
  581. }
  582. });
  583. const hoisted = context.hoist(compoundExpression);
  584. hoisted.constType = 2 /* CAN_HOIST */;
  585. node.props[index] = {
  586. type: 7 /* DIRECTIVE */,
  587. name: 'bind',
  588. arg: compilerCore.createSimpleExpression('srcset', true, attr.loc),
  589. exp: hoisted,
  590. modifiers: [],
  591. loc: attr.loc
  592. };
  593. }
  594. });
  595. }
  596. }
  597. };
  598. function preprocess({ source, filename, preprocessOptions }, preprocessor) {
  599. // Consolidate exposes a callback based API, but the callback is in fact
  600. // called synchronously for most templating engines. In our case, we have to
  601. // expose a synchronous API so that it is usable in Jest transforms (which
  602. // have to be sync because they are applied via Node.js require hooks)
  603. let res = '';
  604. let err = null;
  605. preprocessor.render(source, { filename, ...preprocessOptions }, (_err, _res) => {
  606. if (_err)
  607. err = _err;
  608. res = _res;
  609. });
  610. if (err)
  611. throw err;
  612. return res;
  613. }
  614. function compileTemplate(options) {
  615. const { preprocessLang, preprocessCustomRequire } = options;
  616. const preprocessor = preprocessLang
  617. ? preprocessCustomRequire
  618. ? preprocessCustomRequire(preprocessLang)
  619. : require('consolidate')[preprocessLang]
  620. : false;
  621. if (preprocessor) {
  622. try {
  623. return doCompileTemplate({
  624. ...options,
  625. source: preprocess(options, preprocessor)
  626. });
  627. }
  628. catch (e) {
  629. return {
  630. code: `export default function render() {}`,
  631. source: options.source,
  632. tips: [],
  633. errors: [e]
  634. };
  635. }
  636. }
  637. else if (preprocessLang) {
  638. return {
  639. code: `export default function render() {}`,
  640. source: options.source,
  641. tips: [
  642. `Component ${options.filename} uses lang ${preprocessLang} for template. Please install the language preprocessor.`
  643. ],
  644. errors: [
  645. `Component ${options.filename} uses lang ${preprocessLang} for template, however it is not installed.`
  646. ]
  647. };
  648. }
  649. else {
  650. return doCompileTemplate(options);
  651. }
  652. }
  653. function doCompileTemplate({ filename, id, scoped, inMap, source, ssr = false, ssrCssVars, isProd = false, compiler = ssr ? CompilerSSR__namespace : CompilerDOM__namespace, compilerOptions = {}, transformAssetUrls }) {
  654. const errors = [];
  655. let nodeTransforms = [];
  656. if (shared.isObject(transformAssetUrls)) {
  657. const assetOptions = normalizeOptions(transformAssetUrls);
  658. nodeTransforms = [
  659. createAssetUrlTransformWithOptions(assetOptions),
  660. createSrcsetTransformWithOptions(assetOptions)
  661. ];
  662. }
  663. else if (transformAssetUrls !== false) {
  664. nodeTransforms = [transformAssetUrl, transformSrcset];
  665. }
  666. if (ssr && !ssrCssVars) {
  667. warnOnce(`compileTemplate is called with \`ssr: true\` but no ` +
  668. `corresponding \`cssVars\` option.\`.`);
  669. }
  670. if (!id) {
  671. warnOnce(`compileTemplate now requires the \`id\` option.\`.`);
  672. id = '';
  673. }
  674. const shortId = id.replace(/^data-v-/, '');
  675. const longId = `data-v-${shortId}`;
  676. let { code, ast, preamble, map } = compiler.compile(source, {
  677. mode: 'module',
  678. prefixIdentifiers: true,
  679. hoistStatic: true,
  680. cacheHandlers: true,
  681. ssrCssVars: ssr && ssrCssVars && ssrCssVars.length
  682. ? genCssVarsFromList(ssrCssVars, shortId, isProd)
  683. : '',
  684. scopeId: scoped ? longId : undefined,
  685. ...compilerOptions,
  686. nodeTransforms: nodeTransforms.concat(compilerOptions.nodeTransforms || []),
  687. filename,
  688. sourceMap: true,
  689. onError: e => errors.push(e)
  690. });
  691. // inMap should be the map produced by ./parse.ts which is a simple line-only
  692. // mapping. If it is present, we need to adjust the final map and errors to
  693. // reflect the original line numbers.
  694. if (inMap) {
  695. if (map) {
  696. map = mapLines(inMap, map);
  697. }
  698. if (errors.length) {
  699. patchErrors(errors, source, inMap);
  700. }
  701. }
  702. return { code, ast, preamble, source, errors, tips: [], map };
  703. }
  704. function mapLines(oldMap, newMap) {
  705. if (!oldMap)
  706. return newMap;
  707. if (!newMap)
  708. return oldMap;
  709. const oldMapConsumer = new sourceMap.SourceMapConsumer(oldMap);
  710. const newMapConsumer = new sourceMap.SourceMapConsumer(newMap);
  711. const mergedMapGenerator = new sourceMap.SourceMapGenerator();
  712. newMapConsumer.eachMapping(m => {
  713. if (m.originalLine == null) {
  714. return;
  715. }
  716. const origPosInOldMap = oldMapConsumer.originalPositionFor({
  717. line: m.originalLine,
  718. column: m.originalColumn
  719. });
  720. if (origPosInOldMap.source == null) {
  721. return;
  722. }
  723. mergedMapGenerator.addMapping({
  724. generated: {
  725. line: m.generatedLine,
  726. column: m.generatedColumn
  727. },
  728. original: {
  729. line: origPosInOldMap.line,
  730. // use current column, since the oldMap produced by @vue/compiler-sfc
  731. // does not
  732. column: m.originalColumn
  733. },
  734. source: origPosInOldMap.source,
  735. name: origPosInOldMap.name
  736. });
  737. });
  738. // source-map's type definition is incomplete
  739. const generator = mergedMapGenerator;
  740. oldMapConsumer.sources.forEach((sourceFile) => {
  741. generator._sources.add(sourceFile);
  742. const sourceContent = oldMapConsumer.sourceContentFor(sourceFile);
  743. if (sourceContent != null) {
  744. mergedMapGenerator.setSourceContent(sourceFile, sourceContent);
  745. }
  746. });
  747. generator._sourceRoot = oldMap.sourceRoot;
  748. generator._file = oldMap.file;
  749. return generator.toJSON();
  750. }
  751. function patchErrors(errors, source, inMap) {
  752. const originalSource = inMap.sourcesContent[0];
  753. const offset = originalSource.indexOf(source);
  754. const lineOffset = originalSource.slice(0, offset).split(/\r?\n/).length - 1;
  755. errors.forEach(err => {
  756. if (err.loc) {
  757. err.loc.start.line += lineOffset;
  758. err.loc.start.offset += offset;
  759. if (err.loc.end !== err.loc.start) {
  760. err.loc.end.line += lineOffset;
  761. err.loc.end.offset += offset;
  762. }
  763. }
  764. });
  765. }
  766. const trimPlugin = () => {
  767. return {
  768. postcssPlugin: 'vue-sfc-trim',
  769. Once(root) {
  770. root.walk(({ type, raws }) => {
  771. if (type === 'rule' || type === 'atrule') {
  772. if (raws.before)
  773. raws.before = '\n';
  774. if ('after' in raws && raws.after)
  775. raws.after = '\n';
  776. }
  777. });
  778. }
  779. };
  780. };
  781. trimPlugin.postcss = true;
  782. const animationNameRE = /^(-\w+-)?animation-name$/;
  783. const animationRE = /^(-\w+-)?animation$/;
  784. const scopedPlugin = (id = '') => {
  785. const keyframes = Object.create(null);
  786. const shortId = id.replace(/^data-v-/, '');
  787. return {
  788. postcssPlugin: 'vue-sfc-scoped',
  789. Rule(rule) {
  790. processRule(id, rule);
  791. },
  792. AtRule(node) {
  793. if (/-?keyframes$/.test(node.name) &&
  794. !node.params.endsWith(`-${shortId}`)) {
  795. // register keyframes
  796. keyframes[node.params] = node.params = node.params + '-' + shortId;
  797. }
  798. },
  799. OnceExit(root) {
  800. if (Object.keys(keyframes).length) {
  801. // If keyframes are found in this <style>, find and rewrite animation names
  802. // in declarations.
  803. // Caveat: this only works for keyframes and animation rules in the same
  804. // <style> element.
  805. // individual animation-name declaration
  806. root.walkDecls(decl => {
  807. if (animationNameRE.test(decl.prop)) {
  808. decl.value = decl.value
  809. .split(',')
  810. .map(v => keyframes[v.trim()] || v.trim())
  811. .join(',');
  812. }
  813. // shorthand
  814. if (animationRE.test(decl.prop)) {
  815. decl.value = decl.value
  816. .split(',')
  817. .map(v => {
  818. const vals = v.trim().split(/\s+/);
  819. const i = vals.findIndex(val => keyframes[val]);
  820. if (i !== -1) {
  821. vals.splice(i, 1, keyframes[vals[i]]);
  822. return vals.join(' ');
  823. }
  824. else {
  825. return v;
  826. }
  827. })
  828. .join(',');
  829. }
  830. });
  831. }
  832. }
  833. };
  834. };
  835. const processedRules = new WeakSet();
  836. function processRule(id, rule) {
  837. if (processedRules.has(rule)) {
  838. return;
  839. }
  840. processedRules.add(rule);
  841. rule.selector = selectorParser__default(selectorRoot => {
  842. selectorRoot.each(selector => {
  843. rewriteSelector(id, selector, selectorRoot);
  844. });
  845. }).processSync(rule.selector);
  846. }
  847. function rewriteSelector(id, selector, selectorRoot, slotted = false) {
  848. let node = null;
  849. let shouldInject = true;
  850. // find the last child node to insert attribute selector
  851. selector.each(n => {
  852. // DEPRECATED ">>>" and "/deep/" combinator
  853. if (n.type === 'combinator' &&
  854. (n.value === '>>>' || n.value === '/deep/')) {
  855. n.value = ' ';
  856. n.spaces.before = n.spaces.after = '';
  857. warn(`the >>> and /deep/ combinators have been deprecated. ` +
  858. `Use :deep() instead.`);
  859. return false;
  860. }
  861. if (n.type === 'pseudo') {
  862. const { value } = n;
  863. // deep: inject [id] attribute at the node before the ::v-deep
  864. // combinator.
  865. if (value === ':deep' || value === '::v-deep') {
  866. if (n.nodes.length) {
  867. // .foo ::v-deep(.bar) -> .foo[xxxxxxx] .bar
  868. // replace the current node with ::v-deep's inner selector
  869. let last = n;
  870. n.nodes[0].each(ss => {
  871. selector.insertAfter(last, ss);
  872. last = ss;
  873. });
  874. // insert a space combinator before if it doesn't already have one
  875. const prev = selector.at(selector.index(n) - 1);
  876. if (!prev || !isSpaceCombinator(prev)) {
  877. selector.insertAfter(n, selectorParser__default.combinator({
  878. value: ' '
  879. }));
  880. }
  881. selector.removeChild(n);
  882. }
  883. else {
  884. // DEPRECATED usage
  885. // .foo ::v-deep .bar -> .foo[xxxxxxx] .bar
  886. warn(`::v-deep usage as a combinator has ` +
  887. `been deprecated. Use :deep(<inner-selector>) instead.`);
  888. const prev = selector.at(selector.index(n) - 1);
  889. if (prev && isSpaceCombinator(prev)) {
  890. selector.removeChild(prev);
  891. }
  892. selector.removeChild(n);
  893. }
  894. return false;
  895. }
  896. // slot: use selector inside `::v-slotted` and inject [id + '-s']
  897. // instead.
  898. // ::v-slotted(.foo) -> .foo[xxxxxxx-s]
  899. if (value === ':slotted' || value === '::v-slotted') {
  900. rewriteSelector(id, n.nodes[0], selectorRoot, true /* slotted */);
  901. let last = n;
  902. n.nodes[0].each(ss => {
  903. selector.insertAfter(last, ss);
  904. last = ss;
  905. });
  906. // selector.insertAfter(n, n.nodes[0])
  907. selector.removeChild(n);
  908. // since slotted attribute already scopes the selector there's no
  909. // need for the non-slot attribute.
  910. shouldInject = false;
  911. return false;
  912. }
  913. // global: replace with inner selector and do not inject [id].
  914. // ::v-global(.foo) -> .foo
  915. if (value === ':global' || value === '::v-global') {
  916. selectorRoot.insertAfter(selector, n.nodes[0]);
  917. selectorRoot.removeChild(selector);
  918. return false;
  919. }
  920. }
  921. if (n.type !== 'pseudo' && n.type !== 'combinator') {
  922. node = n;
  923. }
  924. });
  925. if (node) {
  926. node.spaces.after = '';
  927. }
  928. else {
  929. // For deep selectors & standalone pseudo selectors,
  930. // the attribute selectors are prepended rather than appended.
  931. // So all leading spaces must be eliminated to avoid problems.
  932. selector.first.spaces.before = '';
  933. }
  934. if (shouldInject) {
  935. const idToAdd = slotted ? id + '-s' : id;
  936. selector.insertAfter(
  937. // If node is null it means we need to inject [id] at the start
  938. // insertAfter can handle `null` here
  939. node, selectorParser__default.attribute({
  940. attribute: idToAdd,
  941. value: idToAdd,
  942. raws: {},
  943. quoteMark: `"`
  944. }));
  945. }
  946. }
  947. function isSpaceCombinator(node) {
  948. return node.type === 'combinator' && /^\s+$/.test(node.value);
  949. }
  950. scopedPlugin.postcss = true;
  951. // .scss/.sass processor
  952. const scss = (source, map, options, load = require) => {
  953. const nodeSass = load('sass');
  954. const finalOptions = {
  955. ...options,
  956. data: getSource(source, options.filename, options.additionalData),
  957. file: options.filename,
  958. outFile: options.filename,
  959. sourceMap: !!map
  960. };
  961. try {
  962. const result = nodeSass.renderSync(finalOptions);
  963. const dependencies = result.stats.includedFiles;
  964. if (map) {
  965. return {
  966. code: result.css.toString(),
  967. map: merge__default(map, JSON.parse(result.map.toString())),
  968. errors: [],
  969. dependencies
  970. };
  971. }
  972. return { code: result.css.toString(), errors: [], dependencies };
  973. }
  974. catch (e) {
  975. return { code: '', errors: [e], dependencies: [] };
  976. }
  977. };
  978. const sass = (source, map, options, load) => scss(source, map, {
  979. ...options,
  980. indentedSyntax: true
  981. }, load);
  982. // .less
  983. const less = (source, map, options, load = require) => {
  984. const nodeLess = load('less');
  985. let result;
  986. let error = null;
  987. nodeLess.render(getSource(source, options.filename, options.additionalData), { ...options, syncImport: true }, (err, output) => {
  988. error = err;
  989. result = output;
  990. });
  991. if (error)
  992. return { code: '', errors: [error], dependencies: [] };
  993. const dependencies = result.imports;
  994. if (map) {
  995. return {
  996. code: result.css.toString(),
  997. map: merge__default(map, result.map),
  998. errors: [],
  999. dependencies: dependencies
  1000. };
  1001. }
  1002. return {
  1003. code: result.css.toString(),
  1004. errors: [],
  1005. dependencies: dependencies
  1006. };
  1007. };
  1008. // .styl
  1009. const styl = (source, map, options, load = require) => {
  1010. const nodeStylus = load('stylus');
  1011. try {
  1012. const ref = nodeStylus(source);
  1013. Object.keys(options).forEach(key => ref.set(key, options[key]));
  1014. if (map)
  1015. ref.set('sourcemap', { inline: false, comment: false });
  1016. const result = ref.render();
  1017. const dependencies = ref.deps();
  1018. if (map) {
  1019. return {
  1020. code: result,
  1021. map: merge__default(map, ref.sourcemap),
  1022. errors: [],
  1023. dependencies
  1024. };
  1025. }
  1026. return { code: result, errors: [], dependencies };
  1027. }
  1028. catch (e) {
  1029. return { code: '', errors: [e], dependencies: [] };
  1030. }
  1031. };
  1032. function getSource(source, filename, additionalData) {
  1033. if (!additionalData)
  1034. return source;
  1035. if (shared.isFunction(additionalData)) {
  1036. return additionalData(source, filename);
  1037. }
  1038. return additionalData + source;
  1039. }
  1040. const processors = {
  1041. less,
  1042. sass,
  1043. scss,
  1044. styl,
  1045. stylus: styl
  1046. };
  1047. function compileStyle(options) {
  1048. return doCompileStyle({
  1049. ...options,
  1050. isAsync: false
  1051. });
  1052. }
  1053. function compileStyleAsync(options) {
  1054. return doCompileStyle({ ...options, isAsync: true });
  1055. }
  1056. function doCompileStyle(options) {
  1057. const { filename, id, scoped = false, trim = true, isProd = false, modules = false, modulesOptions = {}, preprocessLang, postcssOptions, postcssPlugins } = options;
  1058. const preprocessor = preprocessLang && processors[preprocessLang];
  1059. const preProcessedSource = preprocessor && preprocess$1(options, preprocessor);
  1060. const map = preProcessedSource
  1061. ? preProcessedSource.map
  1062. : options.inMap || options.map;
  1063. const source = preProcessedSource ? preProcessedSource.code : options.source;
  1064. const shortId = id.replace(/^data-v-/, '');
  1065. const longId = `data-v-${shortId}`;
  1066. const plugins = (postcssPlugins || []).slice();
  1067. plugins.unshift(cssVarsPlugin({ id: shortId, isProd }));
  1068. if (trim) {
  1069. plugins.push(trimPlugin());
  1070. }
  1071. if (scoped) {
  1072. plugins.push(scopedPlugin(longId));
  1073. }
  1074. let cssModules;
  1075. if (modules) {
  1076. if (!options.isAsync) {
  1077. throw new Error('[@vue/compiler-sfc] `modules` option can only be used with compileStyleAsync().');
  1078. }
  1079. plugins.push(require('postcss-modules')({
  1080. ...modulesOptions,
  1081. getJSON: (_cssFileName, json) => {
  1082. cssModules = json;
  1083. }
  1084. }));
  1085. }
  1086. const postCSSOptions = {
  1087. ...postcssOptions,
  1088. to: filename,
  1089. from: filename
  1090. };
  1091. if (map) {
  1092. postCSSOptions.map = {
  1093. inline: false,
  1094. annotation: false,
  1095. prev: map
  1096. };
  1097. }
  1098. let result;
  1099. let code;
  1100. let outMap;
  1101. // stylus output include plain css. so need remove the repeat item
  1102. const dependencies = new Set(preProcessedSource ? preProcessedSource.dependencies : []);
  1103. // sass has filename self when provided filename option
  1104. dependencies.delete(filename);
  1105. const errors = [];
  1106. if (preProcessedSource && preProcessedSource.errors.length) {
  1107. errors.push(...preProcessedSource.errors);
  1108. }
  1109. const recordPlainCssDependencies = (messages) => {
  1110. messages.forEach(msg => {
  1111. if (msg.type === 'dependency') {
  1112. // postcss output path is absolute position path
  1113. dependencies.add(msg.file);
  1114. }
  1115. });
  1116. return dependencies;
  1117. };
  1118. try {
  1119. result = postcss__default(plugins).process(source, postCSSOptions);
  1120. // In async mode, return a promise.
  1121. if (options.isAsync) {
  1122. return result
  1123. .then(result => ({
  1124. code: result.css || '',
  1125. map: result.map && result.map.toJSON(),
  1126. errors,
  1127. modules: cssModules,
  1128. rawResult: result,
  1129. dependencies: recordPlainCssDependencies(result.messages)
  1130. }))
  1131. .catch(error => ({
  1132. code: '',
  1133. map: undefined,
  1134. errors: [...errors, error],
  1135. rawResult: undefined,
  1136. dependencies
  1137. }));
  1138. }
  1139. recordPlainCssDependencies(result.messages);
  1140. // force synchronous transform (we know we only have sync plugins)
  1141. code = result.css;
  1142. outMap = result.map;
  1143. }
  1144. catch (e) {
  1145. errors.push(e);
  1146. }
  1147. return {
  1148. code: code || ``,
  1149. map: outMap && outMap.toJSON(),
  1150. errors,
  1151. rawResult: result,
  1152. dependencies
  1153. };
  1154. }
  1155. function preprocess$1(options, preprocessor) {
  1156. return preprocessor(options.source, options.inMap || options.map, {
  1157. filename: options.filename,
  1158. ...options.preprocessOptions
  1159. }, options.preprocessCustomRequire);
  1160. }
  1161. const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/;
  1162. const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/;
  1163. /**
  1164. * Utility for rewriting `export default` in a script block into a variable
  1165. * declaration so that we can inject things into it
  1166. */
  1167. function rewriteDefault(input, as, parserPlugins) {
  1168. if (!hasDefaultExport(input)) {
  1169. return input + `\nconst ${as} = {}`;
  1170. }
  1171. const replaced = input.replace(defaultExportRE, `$1const ${as} =`);
  1172. if (!hasDefaultExport(replaced)) {
  1173. return replaced;
  1174. }
  1175. // if the script somehow still contains `default export`, it probably has
  1176. // multi-line comments or template strings. fallback to a full parse.
  1177. const s = new MagicString__default(input);
  1178. const ast = parser.parse(input, {
  1179. sourceType: 'module',
  1180. plugins: parserPlugins
  1181. }).program.body;
  1182. ast.forEach(node => {
  1183. if (node.type === 'ExportDefaultDeclaration') {
  1184. s.overwrite(node.start, node.declaration.start, `const ${as} = `);
  1185. }
  1186. if (node.type === 'ExportNamedDeclaration') {
  1187. node.specifiers.forEach(specifier => {
  1188. if (specifier.type === 'ExportSpecifier' &&
  1189. specifier.exported.type === 'Identifier' &&
  1190. specifier.exported.name === 'default') {
  1191. const end = specifier.end;
  1192. s.overwrite(specifier.start, input.charAt(end) === ',' ? end + 1 : end, ``);
  1193. s.append(`\nconst ${as} = ${specifier.local.name}`);
  1194. }
  1195. });
  1196. }
  1197. });
  1198. return s.toString();
  1199. }
  1200. function hasDefaultExport(input) {
  1201. return defaultExportRE.test(input) || namedDefaultExportRE.test(input);
  1202. }
  1203. const DEFINE_PROPS = 'defineProps';
  1204. const DEFINE_EMIT = 'defineEmit';
  1205. /**
  1206. * Compile `<script setup>`
  1207. * It requires the whole SFC descriptor because we need to handle and merge
  1208. * normal `<script>` + `<script setup>` if both are present.
  1209. */
  1210. function compileScript(sfc, options) {
  1211. const { script, scriptSetup, source, filename } = sfc;
  1212. if (scriptSetup) {
  1213. warnExperimental(`<script setup>`, 227);
  1214. }
  1215. // for backwards compat
  1216. if (!options) {
  1217. options = { id: '' };
  1218. }
  1219. if (!options.id) {
  1220. warnOnce(`compileScript now requires passing the \`id\` option.\n` +
  1221. `Upgrade your vite or vue-loader version for compatibility with ` +
  1222. `the latest experimental proposals.`);
  1223. }
  1224. const scopeId = options.id ? options.id.replace(/^data-v-/, '') : '';
  1225. const cssVars = sfc.cssVars;
  1226. const hasInheritAttrsFlag = sfc.template && sfc.template.attrs['inherit-attrs'] === 'false';
  1227. const scriptLang = script && script.lang;
  1228. const scriptSetupLang = scriptSetup && scriptSetup.lang;
  1229. const isTS = scriptLang === 'ts' || scriptSetupLang === 'ts';
  1230. const plugins = [...shared.babelParserDefaultPlugins, 'jsx'];
  1231. if (options.babelParserPlugins)
  1232. plugins.push(...options.babelParserPlugins);
  1233. if (isTS)
  1234. plugins.push('typescript', 'decorators-legacy');
  1235. if (!scriptSetup) {
  1236. if (!script) {
  1237. throw new Error(`[@vue/compiler-sfc] SFC contains no <script> tags.`);
  1238. }
  1239. if (scriptLang && scriptLang !== 'ts') {
  1240. // do not process non js/ts script blocks
  1241. return script;
  1242. }
  1243. try {
  1244. const scriptAst = parser.parse(script.content, {
  1245. plugins,
  1246. sourceType: 'module'
  1247. }).program.body;
  1248. const bindings = analyzeScriptBindings(scriptAst);
  1249. const needRewrite = cssVars.length || hasInheritAttrsFlag;
  1250. let content = script.content;
  1251. if (needRewrite) {
  1252. content = rewriteDefault(content, `__default__`, plugins);
  1253. if (cssVars.length) {
  1254. content += genNormalScriptCssVarsCode(cssVars, bindings, scopeId, !!options.isProd);
  1255. }
  1256. if (hasInheritAttrsFlag) {
  1257. content += `__default__.inheritAttrs = false`;
  1258. }
  1259. content += `\nexport default __default__`;
  1260. }
  1261. return {
  1262. ...script,
  1263. content,
  1264. bindings,
  1265. scriptAst
  1266. };
  1267. }
  1268. catch (e) {
  1269. // silently fallback if parse fails since user may be using custom
  1270. // babel syntax
  1271. return script;
  1272. }
  1273. }
  1274. if (script && scriptLang !== scriptSetupLang) {
  1275. throw new Error(`[@vue/compiler-sfc] <script> and <script setup> must have the same language type.`);
  1276. }
  1277. if (scriptSetupLang && scriptSetupLang !== 'ts') {
  1278. // do not process non js/ts script blocks
  1279. return scriptSetup;
  1280. }
  1281. const defaultTempVar = `__default__`;
  1282. const bindingMetadata = {};
  1283. const helperImports = new Set();
  1284. const userImports = Object.create(null);
  1285. const userImportAlias = Object.create(null);
  1286. const setupBindings = Object.create(null);
  1287. const refBindings = Object.create(null);
  1288. const refIdentifiers = new Set();
  1289. const enableRefSugar = options.refSugar !== false;
  1290. let defaultExport;
  1291. let hasDefinePropsCall = false;
  1292. let hasDefineEmitCall = false;
  1293. let propsRuntimeDecl;
  1294. let propsTypeDecl;
  1295. let propsIdentifier;
  1296. let emitRuntimeDecl;
  1297. let emitTypeDecl;
  1298. let emitIdentifier;
  1299. let hasAwait = false;
  1300. let hasInlinedSsrRenderFn = false;
  1301. // props/emits declared via types
  1302. const typeDeclaredProps = {};
  1303. const typeDeclaredEmits = new Set();
  1304. // record declared types for runtime props type generation
  1305. const declaredTypes = {};
  1306. // magic-string state
  1307. const s = new MagicString__default(source);
  1308. const startOffset = scriptSetup.loc.start.offset;
  1309. const endOffset = scriptSetup.loc.end.offset;
  1310. const scriptStartOffset = script && script.loc.start.offset;
  1311. const scriptEndOffset = script && script.loc.end.offset;
  1312. function helper(key) {
  1313. helperImports.add(key);
  1314. return `_${key}`;
  1315. }
  1316. function parse(input, options, offset) {
  1317. try {
  1318. return parser.parse(input, options).program.body;
  1319. }
  1320. catch (e) {
  1321. e.message = `[@vue/compiler-sfc] ${e.message}\n\n${sfc.filename}\n${shared.generateCodeFrame(source, e.pos + offset, e.pos + offset + 1)}`;
  1322. throw e;
  1323. }
  1324. }
  1325. function error(msg, node, end = node.end + startOffset) {
  1326. throw new Error(`[@vue/compiler-sfc] ${msg}\n\n${sfc.filename}\n${shared.generateCodeFrame(source, node.start + startOffset, end)}`);
  1327. }
  1328. function registerUserImport(source, local, imported, isType) {
  1329. if (source === 'vue' && imported) {
  1330. userImportAlias[imported] = local;
  1331. }
  1332. userImports[local] = {
  1333. isType,
  1334. imported: imported || 'default',
  1335. source
  1336. };
  1337. }
  1338. function processDefineProps(node) {
  1339. if (isCallOf(node, DEFINE_PROPS)) {
  1340. if (hasDefinePropsCall) {
  1341. error(`duplicate ${DEFINE_PROPS}() call`, node);
  1342. }
  1343. hasDefinePropsCall = true;
  1344. propsRuntimeDecl = node.arguments[0];
  1345. // context call has type parameters - infer runtime types from it
  1346. if (node.typeParameters) {
  1347. if (propsRuntimeDecl) {
  1348. error(`${DEFINE_PROPS}() cannot accept both type and non-type arguments ` +
  1349. `at the same time. Use one or the other.`, node);
  1350. }
  1351. const typeArg = node.typeParameters.params[0];
  1352. if (typeArg.type === 'TSTypeLiteral') {
  1353. propsTypeDecl = typeArg;
  1354. }
  1355. else {
  1356. error(`type argument passed to ${DEFINE_PROPS}() must be a literal type.`, typeArg);
  1357. }
  1358. }
  1359. return true;
  1360. }
  1361. return false;
  1362. }
  1363. function processDefineEmit(node) {
  1364. if (isCallOf(node, DEFINE_EMIT)) {
  1365. if (hasDefineEmitCall) {
  1366. error(`duplicate ${DEFINE_EMIT}() call`, node);
  1367. }
  1368. hasDefineEmitCall = true;
  1369. emitRuntimeDecl = node.arguments[0];
  1370. if (node.typeParameters) {
  1371. if (emitRuntimeDecl) {
  1372. error(`${DEFINE_EMIT}() cannot accept both type and non-type arguments ` +
  1373. `at the same time. Use one or the other.`, node);
  1374. }
  1375. const typeArg = node.typeParameters.params[0];
  1376. if (typeArg.type === 'TSFunctionType' ||
  1377. typeArg.type === 'TSUnionType') {
  1378. emitTypeDecl = typeArg;
  1379. }
  1380. else {
  1381. error(`type argument passed to ${DEFINE_EMIT}() must be a function type ` +
  1382. `or a union of function types.`, typeArg);
  1383. }
  1384. }
  1385. return true;
  1386. }
  1387. return false;
  1388. }
  1389. function checkInvalidScopeReference(node, method) {
  1390. if (!node)
  1391. return;
  1392. walkIdentifiers(node, id => {
  1393. if (setupBindings[id.name]) {
  1394. error(`\`${method}()\` in <script setup> cannot reference locally ` +
  1395. `declared variables because it will be hoisted outside of the ` +
  1396. `setup() function. If your component options requires initialization ` +
  1397. `in the module scope, use a separate normal <script> to export ` +
  1398. `the options instead.`, id);
  1399. }
  1400. });
  1401. }
  1402. function processRefExpression(exp, statement) {
  1403. if (exp.type === 'AssignmentExpression') {
  1404. const { left, right } = exp;
  1405. if (left.type === 'Identifier') {
  1406. registerRefBinding(left);
  1407. s.prependRight(right.start + startOffset, `${helper('ref')}(`);
  1408. s.appendLeft(right.end + startOffset, ')');
  1409. }
  1410. else if (left.type === 'ObjectPattern') {
  1411. // remove wrapping parens
  1412. for (let i = left.start; i > 0; i--) {
  1413. const char = source[i + startOffset];
  1414. if (char === '(') {
  1415. s.remove(i + startOffset, i + startOffset + 1);
  1416. break;
  1417. }
  1418. }
  1419. for (let i = left.end; i > 0; i++) {
  1420. const char = source[i + startOffset];
  1421. if (char === ')') {
  1422. s.remove(i + startOffset, i + startOffset + 1);
  1423. break;
  1424. }
  1425. }
  1426. processRefObjectPattern(left, statement);
  1427. }
  1428. else if (left.type === 'ArrayPattern') {
  1429. processRefArrayPattern(left, statement);
  1430. }
  1431. }
  1432. else if (exp.type === 'SequenceExpression') {
  1433. // possible multiple declarations
  1434. // ref: x = 1, y = 2
  1435. exp.expressions.forEach(e => processRefExpression(e, statement));
  1436. }
  1437. else if (exp.type === 'Identifier') {
  1438. registerRefBinding(exp);
  1439. s.appendLeft(exp.end + startOffset, ` = ${helper('ref')}()`);
  1440. }
  1441. else {
  1442. error(`ref: statements can only contain assignment expressions.`, exp);
  1443. }
  1444. }
  1445. function registerRefBinding(id) {
  1446. if (id.name[0] === '$') {
  1447. error(`ref variable identifiers cannot start with $.`, id);
  1448. }
  1449. refBindings[id.name] = setupBindings[id.name] = "setup-ref" /* SETUP_REF */;
  1450. refIdentifiers.add(id);
  1451. }
  1452. function processRefObjectPattern(pattern, statement) {
  1453. for (const p of pattern.properties) {
  1454. let nameId;
  1455. if (p.type === 'ObjectProperty') {
  1456. if (p.key.start === p.value.start) {
  1457. // shorthand { foo } --> { foo: __foo }
  1458. nameId = p.key;
  1459. s.appendLeft(nameId.end + startOffset, `: __${nameId.name}`);
  1460. if (p.value.type === 'AssignmentPattern') {
  1461. // { foo = 1 }
  1462. refIdentifiers.add(p.value.left);
  1463. }
  1464. }
  1465. else {
  1466. if (p.value.type === 'Identifier') {
  1467. // { foo: bar } --> { foo: __bar }
  1468. nameId = p.value;
  1469. s.prependRight(nameId.start + startOffset, `__`);
  1470. }
  1471. else if (p.value.type === 'ObjectPattern') {
  1472. processRefObjectPattern(p.value, statement);
  1473. }
  1474. else if (p.value.type === 'ArrayPattern') {
  1475. processRefArrayPattern(p.value, statement);
  1476. }
  1477. else if (p.value.type === 'AssignmentPattern') {
  1478. // { foo: bar = 1 } --> { foo: __bar = 1 }
  1479. nameId = p.value.left;
  1480. s.prependRight(nameId.start + startOffset, `__`);
  1481. }
  1482. }
  1483. }
  1484. else {
  1485. // rest element { ...foo } --> { ...__foo }
  1486. nameId = p.argument;
  1487. s.prependRight(nameId.start + startOffset, `__`);
  1488. }
  1489. if (nameId) {
  1490. registerRefBinding(nameId);
  1491. // append binding declarations after the parent statement
  1492. s.appendLeft(statement.end + startOffset, `\nconst ${nameId.name} = ${helper('ref')}(__${nameId.name});`);
  1493. }
  1494. }
  1495. }
  1496. function processRefArrayPattern(pattern, statement) {
  1497. for (const e of pattern.elements) {
  1498. if (!e)
  1499. continue;
  1500. let nameId;
  1501. if (e.type === 'Identifier') {
  1502. // [a] --> [__a]
  1503. nameId = e;
  1504. }
  1505. else if (e.type === 'AssignmentPattern') {
  1506. // [a = 1] --> [__a = 1]
  1507. nameId = e.left;
  1508. }
  1509. else if (e.type === 'RestElement') {
  1510. // [...a] --> [...__a]
  1511. nameId = e.argument;
  1512. }
  1513. else if (e.type === 'ObjectPattern') {
  1514. processRefObjectPattern(e, statement);
  1515. }
  1516. else if (e.type === 'ArrayPattern') {
  1517. processRefArrayPattern(e, statement);
  1518. }
  1519. if (nameId) {
  1520. registerRefBinding(nameId);
  1521. // prefix original
  1522. s.prependRight(nameId.start + startOffset, `__`);
  1523. // append binding declarations after the parent statement
  1524. s.appendLeft(statement.end + startOffset, `\nconst ${nameId.name} = ${helper('ref')}(__${nameId.name});`);
  1525. }
  1526. }
  1527. }
  1528. // 1. process normal <script> first if it exists
  1529. let scriptAst;
  1530. if (script) {
  1531. // import dedupe between <script> and <script setup>
  1532. scriptAst = parse(script.content, {
  1533. plugins,
  1534. sourceType: 'module'
  1535. }, scriptStartOffset);
  1536. for (const node of scriptAst) {
  1537. if (node.type === 'ImportDeclaration') {
  1538. // record imports for dedupe
  1539. for (const specifier of node.specifiers) {
  1540. const imported = specifier.type === 'ImportSpecifier' &&
  1541. specifier.imported.type === 'Identifier' &&
  1542. specifier.imported.name;
  1543. registerUserImport(node.source.value, specifier.local.name, imported, node.importKind === 'type');
  1544. }
  1545. }
  1546. else if (node.type === 'ExportDefaultDeclaration') {
  1547. // export default
  1548. defaultExport = node;
  1549. const start = node.start + scriptStartOffset;
  1550. s.overwrite(start, start + `export default`.length, `const ${defaultTempVar} =`);
  1551. }
  1552. else if (node.type === 'ExportNamedDeclaration' && node.specifiers) {
  1553. const defaultSpecifier = node.specifiers.find(s => s.exported.type === 'Identifier' && s.exported.name === 'default');
  1554. if (defaultSpecifier) {
  1555. defaultExport = node;
  1556. // 1. remove specifier
  1557. if (node.specifiers.length > 1) {
  1558. s.remove(defaultSpecifier.start + scriptStartOffset, defaultSpecifier.end + scriptStartOffset);
  1559. }
  1560. else {
  1561. s.remove(node.start + scriptStartOffset, node.end + scriptStartOffset);
  1562. }
  1563. if (node.source) {
  1564. // export { x as default } from './x'
  1565. // rewrite to `import { x as __default__ } from './x'` and
  1566. // add to top
  1567. s.prepend(`import { ${defaultSpecifier.local.name} as ${defaultTempVar} } from '${node.source.value}'\n`);
  1568. }
  1569. else {
  1570. // export { x as default }
  1571. // rewrite to `const __default__ = x` and move to end
  1572. s.append(`\nconst ${defaultTempVar} = ${defaultSpecifier.local.name}\n`);
  1573. }
  1574. }
  1575. }
  1576. }
  1577. }
  1578. // 2. parse <script setup> and walk over top level statements
  1579. const scriptSetupAst = parse(scriptSetup.content, {
  1580. plugins: [
  1581. ...plugins,
  1582. // allow top level await but only inside <script setup>
  1583. 'topLevelAwait'
  1584. ],
  1585. sourceType: 'module'
  1586. }, startOffset);
  1587. for (const node of scriptSetupAst) {
  1588. const start = node.start + startOffset;
  1589. let end = node.end + startOffset;
  1590. // import or type declarations: move to top
  1591. // locate comment
  1592. if (node.trailingComments && node.trailingComments.length > 0) {
  1593. const lastCommentNode = node.trailingComments[node.trailingComments.length - 1];
  1594. end = lastCommentNode.end + startOffset;
  1595. }
  1596. // locate the end of whitespace between this statement and the next
  1597. while (end <= source.length) {
  1598. if (!/\s/.test(source.charAt(end))) {
  1599. break;
  1600. }
  1601. end++;
  1602. }
  1603. // process `ref: x` bindings (convert to refs)
  1604. if (node.type === 'LabeledStatement' &&
  1605. node.label.name === 'ref' &&
  1606. node.body.type === 'ExpressionStatement') {
  1607. if (enableRefSugar) {
  1608. warnExperimental(`ref: sugar`, 228);
  1609. s.overwrite(node.label.start + startOffset, node.body.start + startOffset, 'const ');
  1610. processRefExpression(node.body.expression, node);
  1611. }
  1612. else {
  1613. // TODO if we end up shipping ref: sugar as an opt-in feature,
  1614. // need to proxy the option in vite, vue-loader and rollup-plugin-vue.
  1615. error(`ref: sugar needs to be explicitly enabled via vite or vue-loader options.`, node);
  1616. }
  1617. }
  1618. if (node.type === 'ImportDeclaration') {
  1619. // import declarations are moved to top
  1620. s.move(start, end, 0);
  1621. // dedupe imports
  1622. let removed = 0;
  1623. const removeSpecifier = (i) => {
  1624. const removeLeft = i > removed;
  1625. removed++;
  1626. const current = node.specifiers[i];
  1627. const next = node.specifiers[i + 1];
  1628. s.remove(removeLeft
  1629. ? node.specifiers[i - 1].end + startOffset
  1630. : current.start + startOffset, next && !removeLeft
  1631. ? next.start + startOffset
  1632. : current.end + startOffset);
  1633. };
  1634. for (let i = 0; i < node.specifiers.length; i++) {
  1635. const specifier = node.specifiers[i];
  1636. const local = specifier.local.name;
  1637. const imported = specifier.type === 'ImportSpecifier' &&
  1638. specifier.imported.type === 'Identifier' &&
  1639. specifier.imported.name;
  1640. const source = node.source.value;
  1641. const existing = userImports[local];
  1642. if (source === 'vue' &&
  1643. (imported === DEFINE_PROPS || imported === DEFINE_EMIT)) {
  1644. removeSpecifier(i);
  1645. }
  1646. else if (existing) {
  1647. if (existing.source === source && existing.imported === imported) {
  1648. // already imported in <script setup>, dedupe
  1649. removeSpecifier(i);
  1650. }
  1651. else {
  1652. error(`different imports aliased to same local name.`, specifier);
  1653. }
  1654. }
  1655. else {
  1656. registerUserImport(source, local, imported, node.importKind === 'type');
  1657. }
  1658. }
  1659. if (node.specifiers.length && removed === node.specifiers.length) {
  1660. s.remove(node.start + startOffset, node.end + startOffset);
  1661. }
  1662. }
  1663. // process `defineProps` and `defineEmit` calls
  1664. if (node.type === 'ExpressionStatement' &&
  1665. (processDefineProps(node.expression) ||
  1666. processDefineEmit(node.expression))) {
  1667. s.remove(node.start + startOffset, node.end + startOffset);
  1668. }
  1669. if (node.type === 'VariableDeclaration' && !node.declare) {
  1670. for (const decl of node.declarations) {
  1671. if (decl.init) {
  1672. const isDefineProps = processDefineProps(decl.init);
  1673. if (isDefineProps) {
  1674. propsIdentifier = scriptSetup.content.slice(decl.id.start, decl.id.end);
  1675. }
  1676. const isDefineEmit = processDefineEmit(decl.init);
  1677. if (isDefineEmit) {
  1678. emitIdentifier = scriptSetup.content.slice(decl.id.start, decl.id.end);
  1679. }
  1680. if (isDefineProps || isDefineEmit)
  1681. if (node.declarations.length === 1) {
  1682. s.remove(node.start + startOffset, node.end + startOffset);
  1683. }
  1684. else {
  1685. s.remove(decl.start + startOffset, decl.end + startOffset);
  1686. }
  1687. }
  1688. }
  1689. }
  1690. // walk decalrations to record declared bindings
  1691. if ((node.type === 'VariableDeclaration' ||
  1692. node.type === 'FunctionDeclaration' ||
  1693. node.type === 'ClassDeclaration') &&
  1694. !node.declare) {
  1695. walkDeclaration(node, setupBindings, userImportAlias);
  1696. }
  1697. // Type declarations
  1698. if (node.type === 'VariableDeclaration' && node.declare) {
  1699. s.remove(start, end);
  1700. }
  1701. // move all type declarations to outer scope
  1702. if (node.type.startsWith('TS') ||
  1703. (node.type === 'ExportNamedDeclaration' && node.exportKind === 'type')) {
  1704. recordType(node, declaredTypes);
  1705. s.move(start, end, 0);
  1706. }
  1707. // walk statements & named exports / variable declarations for top level
  1708. // await
  1709. if ((node.type === 'VariableDeclaration' && !node.declare) ||
  1710. node.type.endsWith('Statement')) {
  1711. estreeWalker.walk(node, {
  1712. enter(node) {
  1713. if (isFunction(node)) {
  1714. this.skip();
  1715. }
  1716. if (node.type === 'AwaitExpression') {
  1717. hasAwait = true;
  1718. }
  1719. }
  1720. });
  1721. }
  1722. if ((node.type === 'ExportNamedDeclaration' && node.exportKind !== 'type') ||
  1723. node.type === 'ExportAllDeclaration' ||
  1724. node.type === 'ExportDefaultDeclaration') {
  1725. error(`<script setup> cannot contain ES module exports. ` +
  1726. `If you are using a previous version of <script setup>, please ` +
  1727. `consult the updated RFC at https://github.com/vuejs/rfcs/pull/227.`, node);
  1728. }
  1729. }
  1730. // 3. Do a full walk to rewrite identifiers referencing let exports with ref
  1731. // value access
  1732. if (enableRefSugar && Object.keys(refBindings).length) {
  1733. for (const node of scriptSetupAst) {
  1734. if (node.type !== 'ImportDeclaration') {
  1735. walkIdentifiers(node, (id, parent, parentStack) => {
  1736. if (refBindings[id.name] && !refIdentifiers.has(id)) {
  1737. if (isStaticProperty(parent) && parent.shorthand) {
  1738. // let binding used in a property shorthand
  1739. // { foo } -> { foo: foo.value }
  1740. // skip for destructure patterns
  1741. if (!parent.inPattern ||
  1742. isInDestructureAssignment(parent, parentStack)) {
  1743. s.appendLeft(id.end + startOffset, `: ${id.name}.value`);
  1744. }
  1745. }
  1746. else {
  1747. s.appendLeft(id.end + startOffset, '.value');
  1748. }
  1749. }
  1750. else if (id.name[0] === '$' && refBindings[id.name.slice(1)]) {
  1751. // $xxx raw ref access variables, remove the $ prefix
  1752. s.remove(id.start + startOffset, id.start + startOffset + 1);
  1753. }
  1754. });
  1755. }
  1756. }
  1757. }
  1758. // 4. extract runtime props/emits code from setup context type
  1759. if (propsTypeDecl) {
  1760. extractRuntimeProps(propsTypeDecl, typeDeclaredProps, declaredTypes);
  1761. }
  1762. if (emitTypeDecl) {
  1763. extractRuntimeEmits(emitTypeDecl, typeDeclaredEmits);
  1764. }
  1765. // 5. check useOptions args to make sure it doesn't reference setup scope
  1766. // variables
  1767. checkInvalidScopeReference(propsRuntimeDecl, DEFINE_PROPS);
  1768. checkInvalidScopeReference(emitRuntimeDecl, DEFINE_PROPS);
  1769. // 6. remove non-script content
  1770. if (script) {
  1771. if (startOffset < scriptStartOffset) {
  1772. // <script setup> before <script>
  1773. s.remove(0, startOffset);
  1774. s.remove(endOffset, scriptStartOffset);
  1775. s.remove(scriptEndOffset, source.length);
  1776. }
  1777. else {
  1778. // <script> before <script setup>
  1779. s.remove(0, scriptStartOffset);
  1780. s.remove(scriptEndOffset, startOffset);
  1781. s.remove(endOffset, source.length);
  1782. }
  1783. }
  1784. else {
  1785. // only <script setup>
  1786. s.remove(0, startOffset);
  1787. s.remove(endOffset, source.length);
  1788. }
  1789. // 7. analyze binding metadata
  1790. if (scriptAst) {
  1791. Object.assign(bindingMetadata, analyzeScriptBindings(scriptAst));
  1792. }
  1793. if (propsRuntimeDecl) {
  1794. for (const key of getObjectOrArrayExpressionKeys(propsRuntimeDecl)) {
  1795. bindingMetadata[key] = "props" /* PROPS */;
  1796. }
  1797. }
  1798. for (const key in typeDeclaredProps) {
  1799. bindingMetadata[key] = "props" /* PROPS */;
  1800. }
  1801. for (const [key, { isType, imported, source }] of Object.entries(userImports)) {
  1802. if (isType)
  1803. continue;
  1804. bindingMetadata[key] =
  1805. (imported === 'default' && source.endsWith('.vue')) || source === 'vue'
  1806. ? "setup-const" /* SETUP_CONST */
  1807. : "setup-maybe-ref" /* SETUP_MAYBE_REF */;
  1808. }
  1809. for (const key in setupBindings) {
  1810. bindingMetadata[key] = setupBindings[key];
  1811. }
  1812. // 8. inject `useCssVars` calls
  1813. if (cssVars.length) {
  1814. helperImports.add(CSS_VARS_HELPER);
  1815. helperImports.add('unref');
  1816. s.prependRight(startOffset, `\n${genCssVarsCode(cssVars, bindingMetadata, scopeId, !!options.isProd)}\n`);
  1817. }
  1818. // 9. finalize setup() argument signature
  1819. let args = `__props`;
  1820. if (propsTypeDecl) {
  1821. args += `: ${scriptSetup.content.slice(propsTypeDecl.start, propsTypeDecl.end)}`;
  1822. }
  1823. // inject user assignment of props
  1824. // we use a default __props so that template expressions referencing props
  1825. // can use it directly
  1826. if (propsIdentifier) {
  1827. s.prependRight(startOffset, `\nconst ${propsIdentifier} = __props`);
  1828. }
  1829. if (emitIdentifier) {
  1830. args +=
  1831. emitIdentifier === `emit` ? `, { emit }` : `, { emit: ${emitIdentifier} }`;
  1832. if (emitTypeDecl) {
  1833. args += `: {
  1834. emit: (${scriptSetup.content.slice(emitTypeDecl.start, emitTypeDecl.end)}),
  1835. slots: any,
  1836. attrs: any
  1837. }`;
  1838. }
  1839. }
  1840. // 10. generate return statement
  1841. let returned;
  1842. if (options.inlineTemplate) {
  1843. if (sfc.template && !sfc.template.src) {
  1844. if (options.templateOptions && options.templateOptions.ssr) {
  1845. hasInlinedSsrRenderFn = true;
  1846. }
  1847. // inline render function mode - we are going to compile the template and
  1848. // inline it right here
  1849. const { code, ast, preamble, tips, errors } = compileTemplate({
  1850. filename,
  1851. source: sfc.template.content,
  1852. inMap: sfc.template.map,
  1853. ...options.templateOptions,
  1854. id: scopeId,
  1855. scoped: sfc.styles.some(s => s.scoped),
  1856. isProd: options.isProd,
  1857. ssrCssVars: sfc.cssVars,
  1858. compilerOptions: {
  1859. ...(options.templateOptions &&
  1860. options.templateOptions.compilerOptions),
  1861. inline: true,
  1862. isTS,
  1863. bindingMetadata
  1864. }
  1865. });
  1866. if (tips.length) {
  1867. tips.forEach(warnOnce);
  1868. }
  1869. const err = errors[0];
  1870. if (typeof err === 'string') {
  1871. throw new Error(err);
  1872. }
  1873. else if (err) {
  1874. if (err.loc) {
  1875. err.message +=
  1876. `\n\n` +
  1877. sfc.filename +
  1878. '\n' +
  1879. shared.generateCodeFrame(source, err.loc.start.offset, err.loc.end.offset) +
  1880. `\n`;
  1881. }
  1882. throw err;
  1883. }
  1884. if (preamble) {
  1885. s.prepend(preamble);
  1886. }
  1887. // avoid duplicated unref import
  1888. // as this may get injected by the render function preamble OR the
  1889. // css vars codegen
  1890. if (ast && ast.helpers.includes(compilerCore.UNREF)) {
  1891. helperImports.delete('unref');
  1892. }
  1893. returned = code;
  1894. }
  1895. else {
  1896. returned = `() => {}`;
  1897. }
  1898. }
  1899. else {
  1900. // return bindings from setup
  1901. const allBindings = { ...setupBindings };
  1902. for (const key in userImports) {
  1903. if (!userImports[key].isType) {
  1904. allBindings[key] = true;
  1905. }
  1906. }
  1907. returned = `{ ${Object.keys(allBindings).join(', ')} }`;
  1908. }
  1909. s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`);
  1910. // 11. finalize default export
  1911. // expose: [] makes <script setup> components "closed" by default.
  1912. let runtimeOptions = `\n expose: [],`;
  1913. if (hasInheritAttrsFlag) {
  1914. runtimeOptions += `\n inheritAttrs: false,`;
  1915. }
  1916. if (hasInlinedSsrRenderFn) {
  1917. runtimeOptions += `\n __ssrInlineRender: true,`;
  1918. }
  1919. if (propsRuntimeDecl) {
  1920. runtimeOptions += `\n props: ${scriptSetup.content
  1921. .slice(propsRuntimeDecl.start, propsRuntimeDecl.end)
  1922. .trim()},`;
  1923. }
  1924. else if (propsTypeDecl) {
  1925. runtimeOptions += genRuntimeProps(typeDeclaredProps);
  1926. }
  1927. if (emitRuntimeDecl) {
  1928. runtimeOptions += `\n emits: ${scriptSetup.content
  1929. .slice(emitRuntimeDecl.start, emitRuntimeDecl.end)
  1930. .trim()},`;
  1931. }
  1932. else if (emitTypeDecl) {
  1933. runtimeOptions += genRuntimeEmits(typeDeclaredEmits);
  1934. }
  1935. if (isTS) {
  1936. // for TS, make sure the exported type is still valid type with
  1937. // correct props information
  1938. // we have to use object spread for types to be merged properly
  1939. // user's TS setting should compile it down to proper targets
  1940. const def = defaultExport ? `\n ...${defaultTempVar},` : ``;
  1941. // wrap setup code with function.
  1942. // export the content of <script setup> as a named export, `setup`.
  1943. // this allows `import { setup } from '*.vue'` for testing purposes.
  1944. s.prependLeft(startOffset, `\nexport default ${helper(`defineComponent`)}({${def}${runtimeOptions}\n ${hasAwait ? `async ` : ``}setup(${args}) {\n`);
  1945. s.appendRight(endOffset, `})`);
  1946. }
  1947. else {
  1948. if (defaultExport) {
  1949. // can't rely on spread operator in non ts mode
  1950. s.prependLeft(startOffset, `\n${hasAwait ? `async ` : ``}function setup(${args}) {\n`);
  1951. s.append(`\nexport default /*#__PURE__*/ Object.assign(${defaultTempVar}, {${runtimeOptions}\n setup\n})\n`);
  1952. }
  1953. else {
  1954. s.prependLeft(startOffset, `\nexport default {${runtimeOptions}\n ` +
  1955. `${hasAwait ? `async ` : ``}setup(${args}) {\n`);
  1956. s.appendRight(endOffset, `}`);
  1957. }
  1958. }
  1959. // 12. finalize Vue helper imports
  1960. if (helperImports.size > 0) {
  1961. s.prepend(`import { ${[...helperImports]
  1962. .map(h => `${h} as _${h}`)
  1963. .join(', ')} } from 'vue'\n`);
  1964. }
  1965. s.trim();
  1966. return {
  1967. ...scriptSetup,
  1968. bindings: bindingMetadata,
  1969. content: s.toString(),
  1970. map: s.generateMap({
  1971. source: filename,
  1972. hires: true,
  1973. includeContent: true
  1974. }),
  1975. scriptAst,
  1976. scriptSetupAst
  1977. };
  1978. }
  1979. function walkDeclaration(node, bindings, userImportAlias) {
  1980. if (node.type === 'VariableDeclaration') {
  1981. const isConst = node.kind === 'const';
  1982. // export const foo = ...
  1983. for (const { id, init } of node.declarations) {
  1984. const isDefineCall = !!(isConst &&
  1985. (isCallOf(init, DEFINE_PROPS) || isCallOf(init, DEFINE_EMIT)));
  1986. if (id.type === 'Identifier') {
  1987. let bindingType;
  1988. const userReactiveBinding = userImportAlias['reactive'] || 'reactive';
  1989. if (isCallOf(init, userReactiveBinding)) {
  1990. // treat reactive() calls as let since it's meant to be mutable
  1991. bindingType = "setup-let" /* SETUP_LET */;
  1992. }
  1993. else if (
  1994. // if a declaration is a const literal, we can mark it so that
  1995. // the generated render fn code doesn't need to unref() it
  1996. isDefineCall ||
  1997. (isConst && canNeverBeRef(init, userReactiveBinding))) {
  1998. bindingType = "setup-const" /* SETUP_CONST */;
  1999. }
  2000. else if (isConst) {
  2001. if (isCallOf(init, userImportAlias['ref'] || 'ref')) {
  2002. bindingType = "setup-ref" /* SETUP_REF */;
  2003. }
  2004. else {
  2005. bindingType = "setup-maybe-ref" /* SETUP_MAYBE_REF */;
  2006. }
  2007. }
  2008. else {
  2009. bindingType = "setup-let" /* SETUP_LET */;
  2010. }
  2011. bindings[id.name] = bindingType;
  2012. }
  2013. else if (id.type === 'ObjectPattern') {
  2014. walkObjectPattern(id, bindings, isConst, isDefineCall);
  2015. }
  2016. else if (id.type === 'ArrayPattern') {
  2017. walkArrayPattern(id, bindings, isConst, isDefineCall);
  2018. }
  2019. }
  2020. }
  2021. else if (node.type === 'FunctionDeclaration' ||
  2022. node.type === 'ClassDeclaration') {
  2023. // export function foo() {} / export class Foo {}
  2024. // export declarations must be named.
  2025. bindings[node.id.name] = "setup-const" /* SETUP_CONST */;
  2026. }
  2027. }
  2028. function walkObjectPattern(node, bindings, isConst, isDefineCall = false) {
  2029. for (const p of node.properties) {
  2030. if (p.type === 'ObjectProperty') {
  2031. // key can only be Identifier in ObjectPattern
  2032. if (p.key.type === 'Identifier') {
  2033. if (p.key === p.value) {
  2034. // const { x } = ...
  2035. bindings[p.key.name] = isDefineCall
  2036. ? "setup-const" /* SETUP_CONST */
  2037. : isConst
  2038. ? "setup-maybe-ref" /* SETUP_MAYBE_REF */
  2039. : "setup-let" /* SETUP_LET */;
  2040. }
  2041. else {
  2042. walkPattern(p.value, bindings, isConst, isDefineCall);
  2043. }
  2044. }
  2045. }
  2046. else {
  2047. // ...rest
  2048. // argument can only be identifer when destructuring
  2049. bindings[p.argument.name] = isConst
  2050. ? "setup-const" /* SETUP_CONST */
  2051. : "setup-let" /* SETUP_LET */;
  2052. }
  2053. }
  2054. }
  2055. function walkArrayPattern(node, bindings, isConst, isDefineCall = false) {
  2056. for (const e of node.elements) {
  2057. e && walkPattern(e, bindings, isConst, isDefineCall);
  2058. }
  2059. }
  2060. function walkPattern(node, bindings, isConst, isDefineCall = false) {
  2061. if (node.type === 'Identifier') {
  2062. bindings[node.name] = isDefineCall
  2063. ? "setup-const" /* SETUP_CONST */
  2064. : isConst
  2065. ? "setup-maybe-ref" /* SETUP_MAYBE_REF */
  2066. : "setup-let" /* SETUP_LET */;
  2067. }
  2068. else if (node.type === 'RestElement') {
  2069. // argument can only be identifer when destructuring
  2070. bindings[node.argument.name] = isConst
  2071. ? "setup-const" /* SETUP_CONST */
  2072. : "setup-let" /* SETUP_LET */;
  2073. }
  2074. else if (node.type === 'ObjectPattern') {
  2075. walkObjectPattern(node, bindings, isConst);
  2076. }
  2077. else if (node.type === 'ArrayPattern') {
  2078. walkArrayPattern(node, bindings, isConst);
  2079. }
  2080. else if (node.type === 'AssignmentPattern') {
  2081. if (node.left.type === 'Identifier') {
  2082. bindings[node.left.name] = isDefineCall
  2083. ? "setup-const" /* SETUP_CONST */
  2084. : isConst
  2085. ? "setup-maybe-ref" /* SETUP_MAYBE_REF */
  2086. : "setup-let" /* SETUP_LET */;
  2087. }
  2088. else {
  2089. walkPattern(node.left, bindings, isConst);
  2090. }
  2091. }
  2092. }
  2093. function recordType(node, declaredTypes) {
  2094. if (node.type === 'TSInterfaceDeclaration') {
  2095. declaredTypes[node.id.name] = [`Object`];
  2096. }
  2097. else if (node.type === 'TSTypeAliasDeclaration') {
  2098. declaredTypes[node.id.name] = inferRuntimeType(node.typeAnnotation, declaredTypes);
  2099. }
  2100. else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
  2101. recordType(node.declaration, declaredTypes);
  2102. }
  2103. }
  2104. function extractRuntimeProps(node, props, declaredTypes) {
  2105. for (const m of node.members) {
  2106. if (m.type === 'TSPropertySignature' && m.key.type === 'Identifier') {
  2107. props[m.key.name] = {
  2108. key: m.key.name,
  2109. required: !m.optional,
  2110. type: m.typeAnnotation
  2111. ? inferRuntimeType(m.typeAnnotation.typeAnnotation, declaredTypes)
  2112. : [`null`]
  2113. };
  2114. }
  2115. }
  2116. }
  2117. function inferRuntimeType(node, declaredTypes) {
  2118. switch (node.type) {
  2119. case 'TSStringKeyword':
  2120. return ['String'];
  2121. case 'TSNumberKeyword':
  2122. return ['Number'];
  2123. case 'TSBooleanKeyword':
  2124. return ['Boolean'];
  2125. case 'TSObjectKeyword':
  2126. return ['Object'];
  2127. case 'TSTypeLiteral':
  2128. // TODO (nice to have) generate runtime property validation
  2129. return ['Object'];
  2130. case 'TSFunctionType':
  2131. return ['Function'];
  2132. case 'TSArrayType':
  2133. case 'TSTupleType':
  2134. // TODO (nice to have) generate runtime element type/length checks
  2135. return ['Array'];
  2136. case 'TSLiteralType':
  2137. switch (node.literal.type) {
  2138. case 'StringLiteral':
  2139. return ['String'];
  2140. case 'BooleanLiteral':
  2141. return ['Boolean'];
  2142. case 'NumericLiteral':
  2143. case 'BigIntLiteral':
  2144. return ['Number'];
  2145. default:
  2146. return [`null`];
  2147. }
  2148. case 'TSTypeReference':
  2149. if (node.typeName.type === 'Identifier') {
  2150. if (declaredTypes[node.typeName.name]) {
  2151. return declaredTypes[node.typeName.name];
  2152. }
  2153. switch (node.typeName.name) {
  2154. case 'Array':
  2155. case 'Function':
  2156. case 'Object':
  2157. case 'Set':
  2158. case 'Map':
  2159. case 'WeakSet':
  2160. case 'WeakMap':
  2161. return [node.typeName.name];
  2162. case 'Record':
  2163. case 'Partial':
  2164. case 'Readonly':
  2165. case 'Pick':
  2166. case 'Omit':
  2167. case 'Exclude':
  2168. case 'Extract':
  2169. case 'Required':
  2170. case 'InstanceType':
  2171. return ['Object'];
  2172. }
  2173. }
  2174. return [`null`];
  2175. case 'TSUnionType':
  2176. return [
  2177. ...new Set([].concat(node.types.map(t => inferRuntimeType(t, declaredTypes))))
  2178. ];
  2179. case 'TSIntersectionType':
  2180. return ['Object'];
  2181. default:
  2182. return [`null`]; // no runtime check
  2183. }
  2184. }
  2185. function genRuntimeProps(props) {
  2186. const keys = Object.keys(props);
  2187. if (!keys.length) {
  2188. return ``;
  2189. }
  2190. return `\n props: {\n ${keys
  2191. .map(key => {
  2192. const { type, required } = props[key];
  2193. return `${key}: { type: ${toRuntimeTypeString(type)}, required: ${required} }`;
  2194. })
  2195. .join(',\n ')}\n } as unknown as undefined,`;
  2196. }
  2197. function toRuntimeTypeString(types) {
  2198. return types.some(t => t === 'null')
  2199. ? `null`
  2200. : types.length > 1
  2201. ? `[${types.join(', ')}]`
  2202. : types[0];
  2203. }
  2204. function extractRuntimeEmits(node, emits) {
  2205. if (node.type === 'TSUnionType') {
  2206. for (let t of node.types) {
  2207. if (t.type === 'TSParenthesizedType')
  2208. t = t.typeAnnotation;
  2209. if (t.type === 'TSFunctionType') {
  2210. extractRuntimeEmits(t, emits);
  2211. }
  2212. }
  2213. return;
  2214. }
  2215. const eventName = node.parameters[0];
  2216. if (eventName.type === 'Identifier' &&
  2217. eventName.typeAnnotation &&
  2218. eventName.typeAnnotation.type === 'TSTypeAnnotation') {
  2219. const typeNode = eventName.typeAnnotation.typeAnnotation;
  2220. if (typeNode.type === 'TSLiteralType') {
  2221. emits.add(String(typeNode.literal.value));
  2222. }
  2223. else if (typeNode.type === 'TSUnionType') {
  2224. for (const t of typeNode.types) {
  2225. if (t.type === 'TSLiteralType') {
  2226. emits.add(String(t.literal.value));
  2227. }
  2228. }
  2229. }
  2230. }
  2231. }
  2232. function genRuntimeEmits(emits) {
  2233. return emits.size
  2234. ? `\n emits: [${Array.from(emits)
  2235. .map(p => JSON.stringify(p))
  2236. .join(', ')}] as unknown as undefined,`
  2237. : ``;
  2238. }
  2239. /**
  2240. * Walk an AST and find identifiers that are variable references.
  2241. * This is largely the same logic with `transformExpressions` in compiler-core
  2242. * but with some subtle differences as this needs to handle a wider range of
  2243. * possible syntax.
  2244. */
  2245. function walkIdentifiers(root, onIdentifier) {
  2246. const parentStack = [];
  2247. const knownIds = Object.create(null);
  2248. estreeWalker.walk(root, {
  2249. enter(node, parent) {
  2250. parent && parentStack.push(parent);
  2251. if (node.type === 'Identifier') {
  2252. if (!knownIds[node.name] &&
  2253. isRefIdentifier(node, parent, parentStack)) {
  2254. onIdentifier(node, parent, parentStack);
  2255. }
  2256. }
  2257. else if (isFunction(node)) {
  2258. // walk function expressions and add its arguments to known identifiers
  2259. // so that we don't prefix them
  2260. node.params.forEach(p => estreeWalker.walk(p, {
  2261. enter(child, parent) {
  2262. if (child.type === 'Identifier' &&
  2263. // do not record as scope variable if is a destructured key
  2264. !isStaticPropertyKey(child, parent) &&
  2265. // do not record if this is a default value
  2266. // assignment of a destructured variable
  2267. !(parent &&
  2268. parent.type === 'AssignmentPattern' &&
  2269. parent.right === child)) {
  2270. const { name } = child;
  2271. if (node.scopeIds && node.scopeIds.has(name)) {
  2272. return;
  2273. }
  2274. if (name in knownIds) {
  2275. knownIds[name]++;
  2276. }
  2277. else {
  2278. knownIds[name] = 1;
  2279. }
  2280. (node.scopeIds || (node.scopeIds = new Set())).add(name);
  2281. }
  2282. }
  2283. }));
  2284. }
  2285. else if (node.type === 'ObjectProperty' &&
  2286. parent.type === 'ObjectPattern') {
  2287. node.inPattern = true;
  2288. }
  2289. },
  2290. leave(node, parent) {
  2291. parent && parentStack.pop();
  2292. if (node.scopeIds) {
  2293. node.scopeIds.forEach((id) => {
  2294. knownIds[id]--;
  2295. if (knownIds[id] === 0) {
  2296. delete knownIds[id];
  2297. }
  2298. });
  2299. }
  2300. }
  2301. });
  2302. }
  2303. function isRefIdentifier(id, parent, parentStack) {
  2304. // declaration id
  2305. if ((parent.type === 'VariableDeclarator' ||
  2306. parent.type === 'ClassDeclaration') &&
  2307. parent.id === id) {
  2308. return false;
  2309. }
  2310. if (isFunction(parent)) {
  2311. // function decalration/expression id
  2312. if (parent.id === id) {
  2313. return false;
  2314. }
  2315. // params list
  2316. if (parent.params.includes(id)) {
  2317. return false;
  2318. }
  2319. }
  2320. // property key
  2321. // this also covers object destructure pattern
  2322. if (isStaticPropertyKey(id, parent)) {
  2323. return false;
  2324. }
  2325. // non-assignment array destructure pattern
  2326. if (parent.type === 'ArrayPattern' &&
  2327. !isInDestructureAssignment(parent, parentStack)) {
  2328. return false;
  2329. }
  2330. // member expression property
  2331. if ((parent.type === 'MemberExpression' ||
  2332. parent.type === 'OptionalMemberExpression') &&
  2333. parent.property === id &&
  2334. !parent.computed) {
  2335. return false;
  2336. }
  2337. // is a special keyword but parsed as identifier
  2338. if (id.name === 'arguments') {
  2339. return false;
  2340. }
  2341. return true;
  2342. }
  2343. const isStaticProperty = (node) => node &&
  2344. (node.type === 'ObjectProperty' || node.type === 'ObjectMethod') &&
  2345. !node.computed;
  2346. const isStaticPropertyKey = (node, parent) => isStaticProperty(parent) && parent.key === node;
  2347. function isFunction(node) {
  2348. return /Function(?:Expression|Declaration)$|Method$/.test(node.type);
  2349. }
  2350. function isCallOf(node, name) {
  2351. return !!(node &&
  2352. node.type === 'CallExpression' &&
  2353. node.callee.type === 'Identifier' &&
  2354. node.callee.name === name);
  2355. }
  2356. function canNeverBeRef(node, userReactiveImport) {
  2357. if (isCallOf(node, userReactiveImport)) {
  2358. return true;
  2359. }
  2360. switch (node.type) {
  2361. case 'UnaryExpression':
  2362. case 'BinaryExpression':
  2363. case 'ArrayExpression':
  2364. case 'ObjectExpression':
  2365. case 'FunctionExpression':
  2366. case 'ArrowFunctionExpression':
  2367. case 'UpdateExpression':
  2368. case 'ClassExpression':
  2369. case 'TaggedTemplateExpression':
  2370. return true;
  2371. case 'SequenceExpression':
  2372. return canNeverBeRef(node.expressions[node.expressions.length - 1], userReactiveImport);
  2373. default:
  2374. if (node.type.endsWith('Literal')) {
  2375. return true;
  2376. }
  2377. return false;
  2378. }
  2379. }
  2380. function isInDestructureAssignment(parent, parentStack) {
  2381. if (parent &&
  2382. (parent.type === 'ObjectProperty' || parent.type === 'ArrayPattern')) {
  2383. let i = parentStack.length;
  2384. while (i--) {
  2385. const p = parentStack[i];
  2386. if (p.type === 'AssignmentExpression') {
  2387. const root = parentStack[0];
  2388. // if this is a ref: destructure, it should be treated like a
  2389. // variable decalration!
  2390. return !(root.type === 'LabeledStatement' && root.label.name === 'ref');
  2391. }
  2392. else if (p.type !== 'ObjectProperty' && !p.type.endsWith('Pattern')) {
  2393. break;
  2394. }
  2395. }
  2396. }
  2397. return false;
  2398. }
  2399. /**
  2400. * Analyze bindings in normal `<script>`
  2401. * Note that `compileScriptSetup` already analyzes bindings as part of its
  2402. * compilation process so this should only be used on single `<script>` SFCs.
  2403. */
  2404. function analyzeScriptBindings(ast) {
  2405. for (const node of ast) {
  2406. if (node.type === 'ExportDefaultDeclaration' &&
  2407. node.declaration.type === 'ObjectExpression') {
  2408. return analyzeBindingsFromOptions(node.declaration);
  2409. }
  2410. }
  2411. return {};
  2412. }
  2413. function analyzeBindingsFromOptions(node) {
  2414. const bindings = {};
  2415. for (const property of node.properties) {
  2416. if (property.type === 'ObjectProperty' &&
  2417. !property.computed &&
  2418. property.key.type === 'Identifier') {
  2419. // props
  2420. if (property.key.name === 'props') {
  2421. // props: ['foo']
  2422. // props: { foo: ... }
  2423. for (const key of getObjectOrArrayExpressionKeys(property.value)) {
  2424. bindings[key] = "props" /* PROPS */;
  2425. }
  2426. }
  2427. // inject
  2428. else if (property.key.name === 'inject') {
  2429. // inject: ['foo']
  2430. // inject: { foo: {} }
  2431. for (const key of getObjectOrArrayExpressionKeys(property.value)) {
  2432. bindings[key] = "options" /* OPTIONS */;
  2433. }
  2434. }
  2435. // computed & methods
  2436. else if (property.value.type === 'ObjectExpression' &&
  2437. (property.key.name === 'computed' || property.key.name === 'methods')) {
  2438. // methods: { foo() {} }
  2439. // computed: { foo() {} }
  2440. for (const key of getObjectExpressionKeys(property.value)) {
  2441. bindings[key] = "options" /* OPTIONS */;
  2442. }
  2443. }
  2444. }
  2445. // setup & data
  2446. else if (property.type === 'ObjectMethod' &&
  2447. property.key.type === 'Identifier' &&
  2448. (property.key.name === 'setup' || property.key.name === 'data')) {
  2449. for (const bodyItem of property.body.body) {
  2450. // setup() {
  2451. // return {
  2452. // foo: null
  2453. // }
  2454. // }
  2455. if (bodyItem.type === 'ReturnStatement' &&
  2456. bodyItem.argument &&
  2457. bodyItem.argument.type === 'ObjectExpression') {
  2458. for (const key of getObjectExpressionKeys(bodyItem.argument)) {
  2459. bindings[key] =
  2460. property.key.name === 'setup'
  2461. ? "setup-maybe-ref" /* SETUP_MAYBE_REF */
  2462. : "data" /* DATA */;
  2463. }
  2464. }
  2465. }
  2466. }
  2467. }
  2468. return bindings;
  2469. }
  2470. function getObjectExpressionKeys(node) {
  2471. const keys = [];
  2472. for (const prop of node.properties) {
  2473. if ((prop.type === 'ObjectProperty' || prop.type === 'ObjectMethod') &&
  2474. !prop.computed) {
  2475. if (prop.key.type === 'Identifier') {
  2476. keys.push(prop.key.name);
  2477. }
  2478. else if (prop.key.type === 'StringLiteral') {
  2479. keys.push(prop.key.value);
  2480. }
  2481. }
  2482. }
  2483. return keys;
  2484. }
  2485. function getArrayExpressionKeys(node) {
  2486. const keys = [];
  2487. for (const element of node.elements) {
  2488. if (element && element.type === 'StringLiteral') {
  2489. keys.push(element.value);
  2490. }
  2491. }
  2492. return keys;
  2493. }
  2494. function getObjectOrArrayExpressionKeys(value) {
  2495. if (value.type === 'ArrayExpression') {
  2496. return getArrayExpressionKeys(value);
  2497. }
  2498. if (value.type === 'ObjectExpression') {
  2499. return getObjectExpressionKeys(value);
  2500. }
  2501. return [];
  2502. }
  2503. exports.generateCodeFrame = compilerCore.generateCodeFrame;
  2504. exports.compileScript = compileScript;
  2505. exports.compileStyle = compileStyle;
  2506. exports.compileStyleAsync = compileStyleAsync;
  2507. exports.compileTemplate = compileTemplate;
  2508. exports.parse = parse;
  2509. exports.rewriteDefault = rewriteDefault;