版博士V2.0程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

2622 lines
101 KiB

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