compiler-sfc.cjs.js 95 KB

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