12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561 |
- 'use strict';
- Object.defineProperty(exports, '__esModule', { value: true });
- var CompilerDOM = require('@vue/compiler-dom');
- var sourceMap = require('source-map');
- var hash = require('hash-sum');
- var path = require('path');
- var compilerCore = require('@vue/compiler-core');
- var url = require('url');
- var shared = require('@vue/shared');
- var CompilerSSR = require('@vue/compiler-ssr');
- var postcss = require('postcss');
- var selectorParser = require('postcss-selector-parser');
- var merge = require('merge-source-map');
- var MagicString = require('magic-string');
- var parser = require('@babel/parser');
- var estreeWalker = require('estree-walker');
- var refTransform = require('@vue/ref-transform');
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e['default'] : e; }
- function _interopNamespace(e) {
- if (e && e.__esModule) return e;
- var n = Object.create(null);
- if (e) {
- Object.keys(e).forEach(function (k) {
- n[k] = e[k];
- });
- }
- n['default'] = e;
- return Object.freeze(n);
- }
- var CompilerDOM__namespace = /*#__PURE__*/_interopNamespace(CompilerDOM);
- var hash__default = /*#__PURE__*/_interopDefaultLegacy(hash);
- var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
- var CompilerSSR__namespace = /*#__PURE__*/_interopNamespace(CompilerSSR);
- var postcss__default = /*#__PURE__*/_interopDefaultLegacy(postcss);
- var selectorParser__default = /*#__PURE__*/_interopDefaultLegacy(selectorParser);
- var merge__default = /*#__PURE__*/_interopDefaultLegacy(merge);
- var MagicString__default = /*#__PURE__*/_interopDefaultLegacy(MagicString);
- const CSS_VARS_HELPER = `useCssVars`;
- const cssVarRE = /\bv-bind\(\s*(?:'([^']+)'|"([^"]+)"|([^'"][^)]*))\s*\)/g;
- function genCssVarsFromList(vars, id, isProd) {
- return `{\n ${vars
- .map(key => `"${genVarName(id, key, isProd)}": (${key})`)
- .join(',\n ')}\n}`;
- }
- function genVarName(id, raw, isProd) {
- if (isProd) {
- return hash__default(id + raw);
- }
- else {
- return `${id}-${raw.replace(/([^\w-])/g, '_')}`;
- }
- }
- function parseCssVars(sfc) {
- const vars = [];
- sfc.styles.forEach(style => {
- let match;
- // ignore v-bind() in comments /* ... */
- const content = style.content.replace(/\/\*([\s\S]*?)\*\//g, '');
- while ((match = cssVarRE.exec(content))) {
- const variable = match[1] || match[2] || match[3];
- if (!vars.includes(variable)) {
- vars.push(variable);
- }
- }
- });
- return vars;
- }
- const cssVarsPlugin = opts => {
- const { id, isProd } = opts;
- return {
- postcssPlugin: 'vue-sfc-vars',
- Declaration(decl) {
- // rewrite CSS variables
- if (cssVarRE.test(decl.value)) {
- decl.value = decl.value.replace(cssVarRE, (_, $1, $2, $3) => {
- return `var(--${genVarName(id, $1 || $2 || $3, isProd)})`;
- });
- }
- }
- };
- };
- cssVarsPlugin.postcss = true;
- function genCssVarsCode(vars, bindings, id, isProd) {
- const varsExp = genCssVarsFromList(vars, id, isProd);
- const exp = CompilerDOM.createSimpleExpression(varsExp, false);
- const context = CompilerDOM.createTransformContext(CompilerDOM.createRoot([]), {
- prefixIdentifiers: true,
- inline: true,
- bindingMetadata: bindings.__isScriptSetup === false ? undefined : bindings
- });
- const transformed = CompilerDOM.processExpression(exp, context);
- const transformedString = transformed.type === 4 /* SIMPLE_EXPRESSION */
- ? transformed.content
- : transformed.children
- .map(c => {
- return typeof c === 'string'
- ? c
- : c.content;
- })
- .join('');
- return `_${CSS_VARS_HELPER}(_ctx => (${transformedString}))`;
- }
- // <script setup> already gets the calls injected as part of the transform
- // this is only for single normal <script>
- function genNormalScriptCssVarsCode(cssVars, bindings, id, isProd) {
- return (`\nimport { ${CSS_VARS_HELPER} as _${CSS_VARS_HELPER} } from 'vue'\n` +
- `const __injectCSSVars__ = () => {\n${genCssVarsCode(cssVars, bindings, id, isProd)}}\n` +
- `const __setup__ = __default__.setup\n` +
- `__default__.setup = __setup__\n` +
- ` ? (props, ctx) => { __injectCSSVars__();return __setup__(props, ctx) }\n` +
- ` : __injectCSSVars__\n`);
- }
- function createCache(size = 500) {
- return new (require('lru-cache'))(size);
- }
- const sourceToSFC = createCache();
- function parse(source, { sourceMap = true, filename = 'anonymous.vue', sourceRoot = '', pad = false, ignoreEmpty = true, compiler = CompilerDOM__namespace } = {}) {
- const sourceKey = source + sourceMap + filename + sourceRoot + pad + compiler.parse;
- const cache = sourceToSFC.get(sourceKey);
- if (cache) {
- return cache;
- }
- const descriptor = {
- filename,
- source,
- template: null,
- script: null,
- scriptSetup: null,
- styles: [],
- customBlocks: [],
- cssVars: [],
- slotted: false
- };
- const errors = [];
- const ast = compiler.parse(source, {
- // there are no components at SFC parsing level
- isNativeTag: () => true,
- // preserve all whitespaces
- isPreTag: () => true,
- getTextMode: ({ tag, props }, parent) => {
- // all top level elements except <template> are parsed as raw text
- // containers
- if ((!parent && tag !== 'template') ||
- // <template lang="xxx"> should also be treated as raw text
- (tag === 'template' &&
- props.some(p => p.type === 6 /* ATTRIBUTE */ &&
- p.name === 'lang' &&
- p.value &&
- p.value.content &&
- p.value.content !== 'html'))) {
- return 2 /* RAWTEXT */;
- }
- else {
- return 0 /* DATA */;
- }
- },
- onError: e => {
- errors.push(e);
- }
- });
- ast.children.forEach(node => {
- if (node.type !== 1 /* ELEMENT */) {
- return;
- }
- // we only want to keep the nodes that are not empty (when the tag is not a template)
- if (ignoreEmpty &&
- node.tag !== 'template' &&
- isEmpty(node) &&
- !hasSrc(node)) {
- return;
- }
- switch (node.tag) {
- case 'template':
- if (!descriptor.template) {
- const templateBlock = (descriptor.template = createBlock(node, source, false));
- templateBlock.ast = node;
- // warn against 2.x <template functional>
- if (templateBlock.attrs.functional) {
- const err = new SyntaxError(`<template functional> is no longer supported in Vue 3, since ` +
- `functional components no longer have significant performance ` +
- `difference from stateful ones. Just use a normal <template> ` +
- `instead.`);
- err.loc = node.props.find(p => p.name === 'functional').loc;
- errors.push(err);
- }
- }
- else {
- errors.push(createDuplicateBlockError(node));
- }
- break;
- case 'script':
- const scriptBlock = createBlock(node, source, pad);
- const isSetup = !!scriptBlock.attrs.setup;
- if (isSetup && !descriptor.scriptSetup) {
- descriptor.scriptSetup = scriptBlock;
- break;
- }
- if (!isSetup && !descriptor.script) {
- descriptor.script = scriptBlock;
- break;
- }
- errors.push(createDuplicateBlockError(node, isSetup));
- break;
- case 'style':
- const styleBlock = createBlock(node, source, pad);
- if (styleBlock.attrs.vars) {
- errors.push(new SyntaxError(`<style vars> has been replaced by a new proposal: ` +
- `https://github.com/vuejs/rfcs/pull/231`));
- }
- descriptor.styles.push(styleBlock);
- break;
- default:
- descriptor.customBlocks.push(createBlock(node, source, pad));
- break;
- }
- });
- if (descriptor.scriptSetup) {
- if (descriptor.scriptSetup.src) {
- errors.push(new SyntaxError(`<script setup> cannot use the "src" attribute because ` +
- `its syntax will be ambiguous outside of the component.`));
- descriptor.scriptSetup = null;
- }
- if (descriptor.script && descriptor.script.src) {
- errors.push(new SyntaxError(`<script> cannot use the "src" attribute when <script setup> is ` +
- `also present because they must be processed together.`));
- descriptor.script = null;
- }
- }
- if (sourceMap) {
- const genMap = (block) => {
- if (block && !block.src) {
- block.map = generateSourceMap(filename, source, block.content, sourceRoot, !pad || block.type === 'template' ? block.loc.start.line - 1 : 0);
- }
- };
- genMap(descriptor.template);
- genMap(descriptor.script);
- descriptor.styles.forEach(genMap);
- descriptor.customBlocks.forEach(genMap);
- }
- // parse CSS vars
- descriptor.cssVars = parseCssVars(descriptor);
- // check if the SFC uses :slotted
- const slottedRE = /(?:::v-|:)slotted\(/;
- descriptor.slotted = descriptor.styles.some(s => s.scoped && slottedRE.test(s.content));
- const result = {
- descriptor,
- errors
- };
- sourceToSFC.set(sourceKey, result);
- return result;
- }
- function createDuplicateBlockError(node, isScriptSetup = false) {
- const err = new SyntaxError(`Single file component can contain only one <${node.tag}${isScriptSetup ? ` setup` : ``}> element`);
- err.loc = node.loc;
- return err;
- }
- function createBlock(node, source, pad) {
- const type = node.tag;
- let { start, end } = node.loc;
- let content = '';
- if (node.children.length) {
- start = node.children[0].loc.start;
- end = node.children[node.children.length - 1].loc.end;
- content = source.slice(start.offset, end.offset);
- }
- else {
- const offset = node.loc.source.indexOf(`</`);
- if (offset > -1) {
- start = {
- line: start.line,
- column: start.column + offset,
- offset: start.offset + offset
- };
- }
- end = Object.assign({}, start);
- }
- const loc = {
- source: content,
- start,
- end
- };
- const attrs = {};
- const block = {
- type,
- content,
- loc,
- attrs
- };
- if (pad) {
- block.content = padContent(source, block, pad) + block.content;
- }
- node.props.forEach(p => {
- if (p.type === 6 /* ATTRIBUTE */) {
- attrs[p.name] = p.value ? p.value.content || true : true;
- if (p.name === 'lang') {
- block.lang = p.value && p.value.content;
- }
- else if (p.name === 'src') {
- block.src = p.value && p.value.content;
- }
- else if (type === 'style') {
- if (p.name === 'scoped') {
- block.scoped = true;
- }
- else if (p.name === 'module') {
- block.module = attrs[p.name];
- }
- }
- else if (type === 'script' && p.name === 'setup') {
- block.setup = attrs.setup;
- }
- }
- });
- return block;
- }
- const splitRE = /\r?\n/g;
- const emptyRE = /^(?:\/\/)?\s*$/;
- const replaceRE = /./g;
- function generateSourceMap(filename, source, generated, sourceRoot, lineOffset) {
- const map = new sourceMap.SourceMapGenerator({
- file: filename.replace(/\\/g, '/'),
- sourceRoot: sourceRoot.replace(/\\/g, '/')
- });
- map.setSourceContent(filename, source);
- generated.split(splitRE).forEach((line, index) => {
- if (!emptyRE.test(line)) {
- const originalLine = index + 1 + lineOffset;
- const generatedLine = index + 1;
- for (let i = 0; i < line.length; i++) {
- if (!/\s/.test(line[i])) {
- map.addMapping({
- source: filename,
- original: {
- line: originalLine,
- column: i
- },
- generated: {
- line: generatedLine,
- column: i
- }
- });
- }
- }
- }
- });
- return JSON.parse(map.toString());
- }
- function padContent(content, block, pad) {
- content = content.slice(0, block.loc.start.offset);
- if (pad === 'space') {
- return content.replace(replaceRE, ' ');
- }
- else {
- const offset = content.split(splitRE).length;
- const padChar = block.type === 'script' && !block.lang ? '//\n' : '\n';
- return Array(offset).join(padChar);
- }
- }
- function hasSrc(node) {
- return node.props.some(p => {
- if (p.type !== 6 /* ATTRIBUTE */) {
- return false;
- }
- return p.name === 'src';
- });
- }
- /**
- * Returns true if the node has no children
- * once the empty text nodes (trimmed content) have been filtered out.
- */
- function isEmpty(node) {
- return (node.children.filter(child => child.type !== 2 /* TEXT */ || child.content.trim() !== '').length === 0);
- }
- function isRelativeUrl(url) {
- const firstChar = url.charAt(0);
- return firstChar === '.' || firstChar === '~' || firstChar === '@';
- }
- const externalRE = /^https?:\/\//;
- function isExternalUrl(url) {
- return externalRE.test(url);
- }
- const dataUrlRE = /^\s*data:/i;
- function isDataUrl(url) {
- return dataUrlRE.test(url);
- }
- /**
- * Parses string url into URL object.
- */
- function parseUrl(url) {
- const firstChar = url.charAt(0);
- if (firstChar === '~') {
- const secondChar = url.charAt(1);
- url = url.slice(secondChar === '/' ? 2 : 1);
- }
- return parseUriParts(url);
- }
- /**
- * vuejs/component-compiler-utils#22 Support uri fragment in transformed require
- * @param urlString an url as a string
- */
- function parseUriParts(urlString) {
- // A TypeError is thrown if urlString is not a string
- // @see https://nodejs.org/api/url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost
- return url.parse(shared.isString(urlString) ? urlString : '', false, true);
- }
- const defaultAssetUrlOptions = {
- base: null,
- includeAbsolute: false,
- tags: {
- video: ['src', 'poster'],
- source: ['src'],
- img: ['src'],
- image: ['xlink:href', 'href'],
- use: ['xlink:href', 'href']
- }
- };
- const normalizeOptions = (options) => {
- if (Object.keys(options).some(key => shared.isArray(options[key]))) {
- // legacy option format which directly passes in tags config
- return Object.assign(Object.assign({}, defaultAssetUrlOptions), { tags: options });
- }
- return Object.assign(Object.assign({}, defaultAssetUrlOptions), options);
- };
- const createAssetUrlTransformWithOptions = (options) => {
- return (node, context) => transformAssetUrl(node, context, options);
- };
- /**
- * A `@vue/compiler-core` plugin that transforms relative asset urls into
- * either imports or absolute urls.
- *
- * ``` js
- * // Before
- * createVNode('img', { src: './logo.png' })
- *
- * // After
- * import _imports_0 from './logo.png'
- * createVNode('img', { src: _imports_0 })
- * ```
- */
- const transformAssetUrl = (node, context, options = defaultAssetUrlOptions) => {
- if (node.type === 1 /* ELEMENT */) {
- if (!node.props.length) {
- return;
- }
- const tags = options.tags || defaultAssetUrlOptions.tags;
- const attrs = tags[node.tag];
- const wildCardAttrs = tags['*'];
- if (!attrs && !wildCardAttrs) {
- return;
- }
- const assetAttrs = (attrs || []).concat(wildCardAttrs || []);
- node.props.forEach((attr, index) => {
- if (attr.type !== 6 /* ATTRIBUTE */ ||
- !assetAttrs.includes(attr.name) ||
- !attr.value ||
- isExternalUrl(attr.value.content) ||
- isDataUrl(attr.value.content) ||
- attr.value.content[0] === '#' ||
- (!options.includeAbsolute && !isRelativeUrl(attr.value.content))) {
- return;
- }
- const url = parseUrl(attr.value.content);
- if (options.base && attr.value.content[0] === '.') {
- // explicit base - directly rewrite relative urls into absolute url
- // to avoid generating extra imports
- // Allow for full hostnames provided in options.base
- const base = parseUrl(options.base);
- const protocol = base.protocol || '';
- const host = base.host ? protocol + '//' + base.host : '';
- const basePath = base.path || '/';
- // when packaged in the browser, path will be using the posix-
- // only version provided by rollup-plugin-node-builtins.
- attr.value.content =
- host +
- (path__default.posix || path__default).join(basePath, url.path + (url.hash || ''));
- return;
- }
- // otherwise, transform the url into an import.
- // this assumes a bundler will resolve the import into the correct
- // absolute url (e.g. webpack file-loader)
- const exp = getImportsExpressionExp(url.path, url.hash, attr.loc, context);
- node.props[index] = {
- type: 7 /* DIRECTIVE */,
- name: 'bind',
- arg: compilerCore.createSimpleExpression(attr.name, true, attr.loc),
- exp,
- modifiers: [],
- loc: attr.loc
- };
- });
- }
- };
- function getImportsExpressionExp(path, hash, loc, context) {
- if (path) {
- const existing = context.imports.find(i => i.path === path);
- if (existing) {
- return existing.exp;
- }
- const name = `_imports_${context.imports.length}`;
- const exp = compilerCore.createSimpleExpression(name, false, loc, 2 /* CAN_HOIST */);
- context.imports.push({ exp, path });
- if (hash && path) {
- return context.hoist(compilerCore.createSimpleExpression(`${name} + '${hash}'`, false, loc, 2 /* CAN_HOIST */));
- }
- else {
- return exp;
- }
- }
- else {
- return compilerCore.createSimpleExpression(`''`, false, loc, 2 /* CAN_HOIST */);
- }
- }
- const srcsetTags = ['img', 'source'];
- // http://w3c.github.io/html/semantics-embedded-content.html#ref-for-image-candidate-string-5
- const escapedSpaceCharacters = /( |\\t|\\n|\\f|\\r)+/g;
- const createSrcsetTransformWithOptions = (options) => {
- return (node, context) => transformSrcset(node, context, options);
- };
- const transformSrcset = (node, context, options = defaultAssetUrlOptions) => {
- if (node.type === 1 /* ELEMENT */) {
- if (srcsetTags.includes(node.tag) && node.props.length) {
- node.props.forEach((attr, index) => {
- if (attr.name === 'srcset' && attr.type === 6 /* ATTRIBUTE */) {
- if (!attr.value)
- return;
- const value = attr.value.content;
- if (!value)
- return;
- const imageCandidates = value.split(',').map(s => {
- // The attribute value arrives here with all whitespace, except
- // normal spaces, represented by escape sequences
- const [url, descriptor] = s
- .replace(escapedSpaceCharacters, ' ')
- .trim()
- .split(' ', 2);
- return { url, descriptor };
- });
- // data urls contains comma after the ecoding so we need to re-merge
- // them
- for (let i = 0; i < imageCandidates.length; i++) {
- const { url } = imageCandidates[i];
- if (isDataUrl(url)) {
- imageCandidates[i + 1].url =
- url + ',' + imageCandidates[i + 1].url;
- imageCandidates.splice(i, 1);
- }
- }
- const hasQualifiedUrl = imageCandidates.some(({ url }) => {
- return (!isExternalUrl(url) &&
- !isDataUrl(url) &&
- (options.includeAbsolute || isRelativeUrl(url)));
- });
- // When srcset does not contain any qualified URLs, skip transforming
- if (!hasQualifiedUrl) {
- return;
- }
- if (options.base) {
- const base = options.base;
- const set = [];
- imageCandidates.forEach(({ url, descriptor }) => {
- descriptor = descriptor ? ` ${descriptor}` : ``;
- if (isRelativeUrl(url)) {
- set.push((path__default.posix || path__default).join(base, url) + descriptor);
- }
- else {
- set.push(url + descriptor);
- }
- });
- attr.value.content = set.join(', ');
- return;
- }
- const compoundExpression = compilerCore.createCompoundExpression([], attr.loc);
- imageCandidates.forEach(({ url, descriptor }, index) => {
- if (!isExternalUrl(url) &&
- !isDataUrl(url) &&
- (options.includeAbsolute || isRelativeUrl(url))) {
- const { path } = parseUrl(url);
- let exp;
- if (path) {
- const existingImportsIndex = context.imports.findIndex(i => i.path === path);
- if (existingImportsIndex > -1) {
- exp = compilerCore.createSimpleExpression(`_imports_${existingImportsIndex}`, false, attr.loc, 2 /* CAN_HOIST */);
- }
- else {
- exp = compilerCore.createSimpleExpression(`_imports_${context.imports.length}`, false, attr.loc, 2 /* CAN_HOIST */);
- context.imports.push({ exp, path });
- }
- compoundExpression.children.push(exp);
- }
- }
- else {
- const exp = compilerCore.createSimpleExpression(`"${url}"`, false, attr.loc, 2 /* CAN_HOIST */);
- compoundExpression.children.push(exp);
- }
- const isNotLast = imageCandidates.length - 1 > index;
- if (descriptor && isNotLast) {
- compoundExpression.children.push(` + ' ${descriptor}, ' + `);
- }
- else if (descriptor) {
- compoundExpression.children.push(` + ' ${descriptor}'`);
- }
- else if (isNotLast) {
- compoundExpression.children.push(` + ', ' + `);
- }
- });
- const hoisted = context.hoist(compoundExpression);
- hoisted.constType = 2 /* CAN_HOIST */;
- node.props[index] = {
- type: 7 /* DIRECTIVE */,
- name: 'bind',
- arg: compilerCore.createSimpleExpression('srcset', true, attr.loc),
- exp: hoisted,
- modifiers: [],
- loc: attr.loc
- };
- }
- });
- }
- }
- };
- const hasWarned = {};
- function warnOnce(msg) {
- const isNodeProd = typeof process !== 'undefined' && process.env.NODE_ENV === 'production';
- if (!isNodeProd && !false && !hasWarned[msg]) {
- hasWarned[msg] = true;
- warn(msg);
- }
- }
- function warn(msg) {
- console.warn(`\x1b[1m\x1b[33m[@vue/compiler-sfc]\x1b[0m\x1b[33m ${msg}\x1b[0m\n`);
- }
- function preprocess({ source, filename, preprocessOptions }, preprocessor) {
- // Consolidate exposes a callback based API, but the callback is in fact
- // called synchronously for most templating engines. In our case, we have to
- // expose a synchronous API so that it is usable in Jest transforms (which
- // have to be sync because they are applied via Node.js require hooks)
- let res = '';
- let err = null;
- preprocessor.render(source, Object.assign({ filename }, preprocessOptions), (_err, _res) => {
- if (_err)
- err = _err;
- res = _res;
- });
- if (err)
- throw err;
- return res;
- }
- function compileTemplate(options) {
- const { preprocessLang, preprocessCustomRequire } = options;
- const preprocessor = preprocessLang
- ? preprocessCustomRequire
- ? preprocessCustomRequire(preprocessLang)
- : require('consolidate')[preprocessLang]
- : false;
- if (preprocessor) {
- try {
- return doCompileTemplate(Object.assign(Object.assign({}, options), { source: preprocess(options, preprocessor) }));
- }
- catch (e) {
- return {
- code: `export default function render() {}`,
- source: options.source,
- tips: [],
- errors: [e]
- };
- }
- }
- else if (preprocessLang) {
- return {
- code: `export default function render() {}`,
- source: options.source,
- tips: [
- `Component ${options.filename} uses lang ${preprocessLang} for template. Please install the language preprocessor.`
- ],
- errors: [
- `Component ${options.filename} uses lang ${preprocessLang} for template, however it is not installed.`
- ]
- };
- }
- else {
- return doCompileTemplate(options);
- }
- }
- function doCompileTemplate({ filename, id, scoped, slotted, inMap, source, ssr = false, ssrCssVars, isProd = false, compiler = ssr ? CompilerSSR__namespace : CompilerDOM__namespace, compilerOptions = {}, transformAssetUrls }) {
- const errors = [];
- const warnings = [];
- let nodeTransforms = [];
- if (shared.isObject(transformAssetUrls)) {
- const assetOptions = normalizeOptions(transformAssetUrls);
- nodeTransforms = [
- createAssetUrlTransformWithOptions(assetOptions),
- createSrcsetTransformWithOptions(assetOptions)
- ];
- }
- else if (transformAssetUrls !== false) {
- nodeTransforms = [transformAssetUrl, transformSrcset];
- }
- if (ssr && !ssrCssVars) {
- warnOnce(`compileTemplate is called with \`ssr: true\` but no ` +
- `corresponding \`cssVars\` option.\`.`);
- }
- if (!id) {
- warnOnce(`compileTemplate now requires the \`id\` option.\`.`);
- id = '';
- }
- const shortId = id.replace(/^data-v-/, '');
- const longId = `data-v-${shortId}`;
- let { code, ast, preamble, map } = compiler.compile(source, Object.assign(Object.assign({ mode: 'module', prefixIdentifiers: true, hoistStatic: true, cacheHandlers: true, ssrCssVars: ssr && ssrCssVars && ssrCssVars.length
- ? genCssVarsFromList(ssrCssVars, shortId, isProd)
- : '', scopeId: scoped ? longId : undefined, slotted }, compilerOptions), { nodeTransforms: nodeTransforms.concat(compilerOptions.nodeTransforms || []), filename, sourceMap: true, onError: e => errors.push(e), onWarn: w => warnings.push(w) }));
- // inMap should be the map produced by ./parse.ts which is a simple line-only
- // mapping. If it is present, we need to adjust the final map and errors to
- // reflect the original line numbers.
- if (inMap) {
- if (map) {
- map = mapLines(inMap, map);
- }
- if (errors.length) {
- patchErrors(errors, source, inMap);
- }
- }
- const tips = warnings.map(w => {
- let msg = w.message;
- if (w.loc) {
- msg += `\n${shared.generateCodeFrame(source, w.loc.start.offset, w.loc.end.offset)}`;
- }
- return msg;
- });
- return { code, ast, preamble, source, errors, tips, map };
- }
- function mapLines(oldMap, newMap) {
- if (!oldMap)
- return newMap;
- if (!newMap)
- return oldMap;
- const oldMapConsumer = new sourceMap.SourceMapConsumer(oldMap);
- const newMapConsumer = new sourceMap.SourceMapConsumer(newMap);
- const mergedMapGenerator = new sourceMap.SourceMapGenerator();
- newMapConsumer.eachMapping(m => {
- if (m.originalLine == null) {
- return;
- }
- const origPosInOldMap = oldMapConsumer.originalPositionFor({
- line: m.originalLine,
- column: m.originalColumn
- });
- if (origPosInOldMap.source == null) {
- return;
- }
- mergedMapGenerator.addMapping({
- generated: {
- line: m.generatedLine,
- column: m.generatedColumn
- },
- original: {
- line: origPosInOldMap.line,
- // use current column, since the oldMap produced by @vue/compiler-sfc
- // does not
- column: m.originalColumn
- },
- source: origPosInOldMap.source,
- name: origPosInOldMap.name
- });
- });
- // source-map's type definition is incomplete
- const generator = mergedMapGenerator;
- oldMapConsumer.sources.forEach((sourceFile) => {
- generator._sources.add(sourceFile);
- const sourceContent = oldMapConsumer.sourceContentFor(sourceFile);
- if (sourceContent != null) {
- mergedMapGenerator.setSourceContent(sourceFile, sourceContent);
- }
- });
- generator._sourceRoot = oldMap.sourceRoot;
- generator._file = oldMap.file;
- return generator.toJSON();
- }
- function patchErrors(errors, source, inMap) {
- const originalSource = inMap.sourcesContent[0];
- const offset = originalSource.indexOf(source);
- const lineOffset = originalSource.slice(0, offset).split(/\r?\n/).length - 1;
- errors.forEach(err => {
- if (err.loc) {
- err.loc.start.line += lineOffset;
- err.loc.start.offset += offset;
- if (err.loc.end !== err.loc.start) {
- err.loc.end.line += lineOffset;
- err.loc.end.offset += offset;
- }
- }
- });
- }
- const trimPlugin = () => {
- return {
- postcssPlugin: 'vue-sfc-trim',
- Once(root) {
- root.walk(({ type, raws }) => {
- if (type === 'rule' || type === 'atrule') {
- if (raws.before)
- raws.before = '\n';
- if ('after' in raws && raws.after)
- raws.after = '\n';
- }
- });
- }
- };
- };
- trimPlugin.postcss = true;
- const animationNameRE = /^(-\w+-)?animation-name$/;
- const animationRE = /^(-\w+-)?animation$/;
- const scopedPlugin = (id = '') => {
- const keyframes = Object.create(null);
- const shortId = id.replace(/^data-v-/, '');
- return {
- postcssPlugin: 'vue-sfc-scoped',
- Rule(rule) {
- processRule(id, rule);
- },
- AtRule(node) {
- if (/-?keyframes$/.test(node.name) &&
- !node.params.endsWith(`-${shortId}`)) {
- // register keyframes
- keyframes[node.params] = node.params = node.params + '-' + shortId;
- }
- },
- OnceExit(root) {
- if (Object.keys(keyframes).length) {
- // If keyframes are found in this <style>, find and rewrite animation names
- // in declarations.
- // Caveat: this only works for keyframes and animation rules in the same
- // <style> element.
- // individual animation-name declaration
- root.walkDecls(decl => {
- if (animationNameRE.test(decl.prop)) {
- decl.value = decl.value
- .split(',')
- .map(v => keyframes[v.trim()] || v.trim())
- .join(',');
- }
- // shorthand
- if (animationRE.test(decl.prop)) {
- decl.value = decl.value
- .split(',')
- .map(v => {
- const vals = v.trim().split(/\s+/);
- const i = vals.findIndex(val => keyframes[val]);
- if (i !== -1) {
- vals.splice(i, 1, keyframes[vals[i]]);
- return vals.join(' ');
- }
- else {
- return v;
- }
- })
- .join(',');
- }
- });
- }
- }
- };
- };
- const processedRules = new WeakSet();
- function processRule(id, rule) {
- if (processedRules.has(rule) ||
- (rule.parent &&
- rule.parent.type === 'atrule' &&
- /-?keyframes$/.test(rule.parent.name))) {
- return;
- }
- processedRules.add(rule);
- rule.selector = selectorParser__default(selectorRoot => {
- selectorRoot.each(selector => {
- rewriteSelector(id, selector, selectorRoot);
- });
- }).processSync(rule.selector);
- }
- function rewriteSelector(id, selector, selectorRoot, slotted = false) {
- let node = null;
- let shouldInject = true;
- // find the last child node to insert attribute selector
- selector.each(n => {
- // DEPRECATED ">>>" and "/deep/" combinator
- if (n.type === 'combinator' &&
- (n.value === '>>>' || n.value === '/deep/')) {
- n.value = ' ';
- n.spaces.before = n.spaces.after = '';
- warn(`the >>> and /deep/ combinators have been deprecated. ` +
- `Use :deep() instead.`);
- return false;
- }
- if (n.type === 'pseudo') {
- const { value } = n;
- // deep: inject [id] attribute at the node before the ::v-deep
- // combinator.
- if (value === ':deep' || value === '::v-deep') {
- if (n.nodes.length) {
- // .foo ::v-deep(.bar) -> .foo[xxxxxxx] .bar
- // replace the current node with ::v-deep's inner selector
- let last = n;
- n.nodes[0].each(ss => {
- selector.insertAfter(last, ss);
- last = ss;
- });
- // insert a space combinator before if it doesn't already have one
- const prev = selector.at(selector.index(n) - 1);
- if (!prev || !isSpaceCombinator(prev)) {
- selector.insertAfter(n, selectorParser__default.combinator({
- value: ' '
- }));
- }
- selector.removeChild(n);
- }
- else {
- // DEPRECATED usage
- // .foo ::v-deep .bar -> .foo[xxxxxxx] .bar
- warn(`::v-deep usage as a combinator has ` +
- `been deprecated. Use :deep(<inner-selector>) instead.`);
- const prev = selector.at(selector.index(n) - 1);
- if (prev && isSpaceCombinator(prev)) {
- selector.removeChild(prev);
- }
- selector.removeChild(n);
- }
- return false;
- }
- // slot: use selector inside `::v-slotted` and inject [id + '-s']
- // instead.
- // ::v-slotted(.foo) -> .foo[xxxxxxx-s]
- if (value === ':slotted' || value === '::v-slotted') {
- rewriteSelector(id, n.nodes[0], selectorRoot, true /* slotted */);
- let last = n;
- n.nodes[0].each(ss => {
- selector.insertAfter(last, ss);
- last = ss;
- });
- // selector.insertAfter(n, n.nodes[0])
- selector.removeChild(n);
- // since slotted attribute already scopes the selector there's no
- // need for the non-slot attribute.
- shouldInject = false;
- return false;
- }
- // global: replace with inner selector and do not inject [id].
- // ::v-global(.foo) -> .foo
- if (value === ':global' || value === '::v-global') {
- selectorRoot.insertAfter(selector, n.nodes[0]);
- selectorRoot.removeChild(selector);
- return false;
- }
- }
- if (n.type !== 'pseudo' && n.type !== 'combinator') {
- node = n;
- }
- });
- if (node) {
- node.spaces.after = '';
- }
- else {
- // For deep selectors & standalone pseudo selectors,
- // the attribute selectors are prepended rather than appended.
- // So all leading spaces must be eliminated to avoid problems.
- selector.first.spaces.before = '';
- }
- if (shouldInject) {
- const idToAdd = slotted ? id + '-s' : id;
- selector.insertAfter(
- // If node is null it means we need to inject [id] at the start
- // insertAfter can handle `null` here
- node, selectorParser__default.attribute({
- attribute: idToAdd,
- value: idToAdd,
- raws: {},
- quoteMark: `"`
- }));
- }
- }
- function isSpaceCombinator(node) {
- return node.type === 'combinator' && /^\s+$/.test(node.value);
- }
- scopedPlugin.postcss = true;
- // .scss/.sass processor
- const scss = (source, map, options, load = require) => {
- const nodeSass = load('sass');
- const finalOptions = Object.assign(Object.assign({}, options), { data: getSource(source, options.filename, options.additionalData), file: options.filename, outFile: options.filename, sourceMap: !!map });
- try {
- const result = nodeSass.renderSync(finalOptions);
- const dependencies = result.stats.includedFiles;
- if (map) {
- return {
- code: result.css.toString(),
- map: merge__default(map, JSON.parse(result.map.toString())),
- errors: [],
- dependencies
- };
- }
- return { code: result.css.toString(), errors: [], dependencies };
- }
- catch (e) {
- return { code: '', errors: [e], dependencies: [] };
- }
- };
- const sass = (source, map, options, load) => scss(source, map, Object.assign(Object.assign({}, options), { indentedSyntax: true }), load);
- // .less
- const less = (source, map, options, load = require) => {
- const nodeLess = load('less');
- let result;
- let error = null;
- nodeLess.render(getSource(source, options.filename, options.additionalData), Object.assign(Object.assign({}, options), { syncImport: true }), (err, output) => {
- error = err;
- result = output;
- });
- if (error)
- return { code: '', errors: [error], dependencies: [] };
- const dependencies = result.imports;
- if (map) {
- return {
- code: result.css.toString(),
- map: merge__default(map, result.map),
- errors: [],
- dependencies: dependencies
- };
- }
- return {
- code: result.css.toString(),
- errors: [],
- dependencies: dependencies
- };
- };
- // .styl
- const styl = (source, map, options, load = require) => {
- const nodeStylus = load('stylus');
- try {
- const ref = nodeStylus(source);
- Object.keys(options).forEach(key => ref.set(key, options[key]));
- if (map)
- ref.set('sourcemap', { inline: false, comment: false });
- const result = ref.render();
- const dependencies = ref.deps();
- if (map) {
- return {
- code: result,
- map: merge__default(map, ref.sourcemap),
- errors: [],
- dependencies
- };
- }
- return { code: result, errors: [], dependencies };
- }
- catch (e) {
- return { code: '', errors: [e], dependencies: [] };
- }
- };
- function getSource(source, filename, additionalData) {
- if (!additionalData)
- return source;
- if (shared.isFunction(additionalData)) {
- return additionalData(source, filename);
- }
- return additionalData + source;
- }
- const processors = {
- less,
- sass,
- scss,
- styl,
- stylus: styl
- };
- function compileStyle(options) {
- return doCompileStyle(Object.assign(Object.assign({}, options), { isAsync: false }));
- }
- function compileStyleAsync(options) {
- return doCompileStyle(Object.assign(Object.assign({}, options), { isAsync: true }));
- }
- function doCompileStyle(options) {
- const { filename, id, scoped = false, trim = true, isProd = false, modules = false, modulesOptions = {}, preprocessLang, postcssOptions, postcssPlugins } = options;
- const preprocessor = preprocessLang && processors[preprocessLang];
- const preProcessedSource = preprocessor && preprocess$1(options, preprocessor);
- const map = preProcessedSource
- ? preProcessedSource.map
- : options.inMap || options.map;
- const source = preProcessedSource ? preProcessedSource.code : options.source;
- const shortId = id.replace(/^data-v-/, '');
- const longId = `data-v-${shortId}`;
- const plugins = (postcssPlugins || []).slice();
- plugins.unshift(cssVarsPlugin({ id: shortId, isProd }));
- if (trim) {
- plugins.push(trimPlugin());
- }
- if (scoped) {
- plugins.push(scopedPlugin(longId));
- }
- let cssModules;
- if (modules) {
- if (!options.isAsync) {
- throw new Error('[@vue/compiler-sfc] `modules` option can only be used with compileStyleAsync().');
- }
- plugins.push(require('postcss-modules')(Object.assign(Object.assign({}, modulesOptions), { getJSON: (_cssFileName, json) => {
- cssModules = json;
- } })));
- }
- const postCSSOptions = Object.assign(Object.assign({}, postcssOptions), { to: filename, from: filename });
- if (map) {
- postCSSOptions.map = {
- inline: false,
- annotation: false,
- prev: map
- };
- }
- let result;
- let code;
- let outMap;
- // stylus output include plain css. so need remove the repeat item
- const dependencies = new Set(preProcessedSource ? preProcessedSource.dependencies : []);
- // sass has filename self when provided filename option
- dependencies.delete(filename);
- const errors = [];
- if (preProcessedSource && preProcessedSource.errors.length) {
- errors.push(...preProcessedSource.errors);
- }
- const recordPlainCssDependencies = (messages) => {
- messages.forEach(msg => {
- if (msg.type === 'dependency') {
- // postcss output path is absolute position path
- dependencies.add(msg.file);
- }
- });
- return dependencies;
- };
- try {
- result = postcss__default(plugins).process(source, postCSSOptions);
- // In async mode, return a promise.
- if (options.isAsync) {
- return result
- .then(result => ({
- code: result.css || '',
- map: result.map && result.map.toJSON(),
- errors,
- modules: cssModules,
- rawResult: result,
- dependencies: recordPlainCssDependencies(result.messages)
- }))
- .catch(error => ({
- code: '',
- map: undefined,
- errors: [...errors, error],
- rawResult: undefined,
- dependencies
- }));
- }
- recordPlainCssDependencies(result.messages);
- // force synchronous transform (we know we only have sync plugins)
- code = result.css;
- outMap = result.map;
- }
- catch (e) {
- errors.push(e);
- }
- return {
- code: code || ``,
- map: outMap && outMap.toJSON(),
- errors,
- rawResult: result,
- dependencies
- };
- }
- function preprocess$1(options, preprocessor) {
- return preprocessor(options.source, options.inMap || options.map, Object.assign({ filename: options.filename }, options.preprocessOptions), options.preprocessCustomRequire);
- }
- const defaultExportRE = /((?:^|\n|;)\s*)export(\s*)default/;
- const namedDefaultExportRE = /((?:^|\n|;)\s*)export(.+)as(\s*)default/s;
- const exportDefaultClassRE = /((?:^|\n|;)\s*)export\s+default\s+class\s+([\w$]+)/;
- /**
- * Utility for rewriting `export default` in a script block into a variable
- * declaration so that we can inject things into it
- */
- function rewriteDefault(input, as, parserPlugins) {
- if (!hasDefaultExport(input)) {
- return input + `\nconst ${as} = {}`;
- }
- let replaced;
- const classMatch = input.match(exportDefaultClassRE);
- if (classMatch) {
- replaced =
- input.replace(exportDefaultClassRE, '$1class $2') +
- `\nconst ${as} = ${classMatch[2]}`;
- }
- else {
- replaced = input.replace(defaultExportRE, `$1const ${as} =`);
- }
- if (!hasDefaultExport(replaced)) {
- return replaced;
- }
- // if the script somehow still contains `default export`, it probably has
- // multi-line comments or template strings. fallback to a full parse.
- const s = new MagicString__default(input);
- const ast = parser.parse(input, {
- sourceType: 'module',
- plugins: parserPlugins
- }).program.body;
- ast.forEach(node => {
- if (node.type === 'ExportDefaultDeclaration') {
- s.overwrite(node.start, node.declaration.start, `const ${as} = `);
- }
- if (node.type === 'ExportNamedDeclaration') {
- node.specifiers.forEach(specifier => {
- if (specifier.type === 'ExportSpecifier' &&
- specifier.exported.type === 'Identifier' &&
- specifier.exported.name === 'default') {
- const end = specifier.end;
- s.overwrite(specifier.start, input.charAt(end) === ',' ? end + 1 : end, ``);
- s.append(`\nconst ${as} = ${specifier.local.name}`);
- }
- });
- }
- });
- return s.toString();
- }
- function hasDefaultExport(input) {
- return defaultExportRE.test(input) || namedDefaultExportRE.test(input);
- }
- // Special compiler macros
- const DEFINE_PROPS = 'defineProps';
- const DEFINE_EMITS = 'defineEmits';
- const DEFINE_EXPOSE = 'defineExpose';
- const WITH_DEFAULTS = 'withDefaults';
- const isBuiltInDir = shared.makeMap(`once,memo,if,else,else-if,slot,text,html,on,bind,model,show,cloak,is`);
- /**
- * Compile `<script setup>`
- * It requires the whole SFC descriptor because we need to handle and merge
- * normal `<script>` + `<script setup>` if both are present.
- */
- function compileScript(sfc, options) {
- let { script, scriptSetup, source, filename } = sfc;
- // feature flags
- const enableRefTransform = !!options.refSugar || !!options.refTransform;
- let refBindings;
- // for backwards compat
- if (!options) {
- options = { id: '' };
- }
- if (!options.id) {
- warnOnce(`compileScript now requires passing the \`id\` option.\n` +
- `Upgrade your vite or vue-loader version for compatibility with ` +
- `the latest experimental proposals.`);
- }
- const scopeId = options.id ? options.id.replace(/^data-v-/, '') : '';
- const cssVars = sfc.cssVars;
- const scriptLang = script && script.lang;
- const scriptSetupLang = scriptSetup && scriptSetup.lang;
- const isTS = scriptLang === 'ts' ||
- scriptLang === 'tsx' ||
- scriptSetupLang === 'ts' ||
- scriptSetupLang === 'tsx';
- const plugins = [...shared.babelParserDefaultPlugins];
- if (!isTS || scriptLang === 'tsx' || scriptSetupLang === 'tsx') {
- plugins.push('jsx');
- }
- if (options.babelParserPlugins)
- plugins.push(...options.babelParserPlugins);
- if (isTS)
- plugins.push('typescript', 'decorators-legacy');
- if (!scriptSetup) {
- if (!script) {
- throw new Error(`[@vue/compiler-sfc] SFC contains no <script> tags.`);
- }
- if (scriptLang && !isTS && scriptLang !== 'jsx') {
- // do not process non js/ts script blocks
- return script;
- }
- try {
- let content = script.content;
- let map = script.map;
- const scriptAst = parser.parse(content, {
- plugins,
- sourceType: 'module'
- }).program;
- const bindings = analyzeScriptBindings(scriptAst.body);
- if (enableRefTransform && refTransform.shouldTransform(content)) {
- const s = new MagicString__default(source);
- const startOffset = script.loc.start.offset;
- const endOffset = script.loc.end.offset;
- const { importedHelpers } = refTransform.transformAST(scriptAst, s, startOffset);
- if (importedHelpers.length) {
- s.prepend(`import { ${importedHelpers
- .map(h => `${h} as _${h}`)
- .join(', ')} } from 'vue'\n`);
- }
- s.remove(0, startOffset);
- s.remove(endOffset, source.length);
- content = s.toString();
- map = s.generateMap({
- source: filename,
- hires: true,
- includeContent: true
- });
- }
- if (cssVars.length) {
- content = rewriteDefault(content, `__default__`, plugins);
- content += genNormalScriptCssVarsCode(cssVars, bindings, scopeId, !!options.isProd);
- content += `\nexport default __default__`;
- }
- return Object.assign(Object.assign({}, script), { content,
- map,
- bindings, scriptAst: scriptAst.body });
- }
- catch (e) {
- // silently fallback if parse fails since user may be using custom
- // babel syntax
- return script;
- }
- }
- if (script && scriptLang !== scriptSetupLang) {
- throw new Error(`[@vue/compiler-sfc] <script> and <script setup> must have the same ` +
- `language type.`);
- }
- if (scriptSetupLang && !isTS && scriptSetupLang !== 'jsx') {
- // do not process non js/ts script blocks
- return scriptSetup;
- }
- // metadata that needs to be returned
- const bindingMetadata = {};
- const defaultTempVar = `__default__`;
- const helperImports = new Set();
- const userImports = Object.create(null);
- const userImportAlias = Object.create(null);
- const setupBindings = Object.create(null);
- let defaultExport;
- let hasDefinePropsCall = false;
- let hasDefineEmitCall = false;
- let hasDefineExposeCall = false;
- let propsRuntimeDecl;
- let propsRuntimeDefaults;
- let propsTypeDecl;
- let propsTypeDeclRaw;
- let propsIdentifier;
- let emitsRuntimeDecl;
- let emitsTypeDecl;
- let emitsTypeDeclRaw;
- let emitIdentifier;
- let hasAwait = false;
- let hasInlinedSsrRenderFn = false;
- // props/emits declared via types
- const typeDeclaredProps = {};
- const typeDeclaredEmits = new Set();
- // record declared types for runtime props type generation
- const declaredTypes = {};
- // magic-string state
- const s = new MagicString__default(source);
- const startOffset = scriptSetup.loc.start.offset;
- const endOffset = scriptSetup.loc.end.offset;
- const scriptStartOffset = script && script.loc.start.offset;
- const scriptEndOffset = script && script.loc.end.offset;
- function helper(key) {
- helperImports.add(key);
- return `_${key}`;
- }
- function parse(input, options, offset) {
- try {
- return parser.parse(input, options).program;
- }
- catch (e) {
- e.message = `[@vue/compiler-sfc] ${e.message}\n\n${sfc.filename}\n${shared.generateCodeFrame(source, e.pos + offset, e.pos + offset + 1)}`;
- throw e;
- }
- }
- function error(msg, node, end = node.end + startOffset) {
- throw new Error(`[@vue/compiler-sfc] ${msg}\n\n${sfc.filename}\n${shared.generateCodeFrame(source, node.start + startOffset, end)}`);
- }
- function registerUserImport(source, local, imported, isType, isFromSetup) {
- if (source === 'vue' && imported) {
- userImportAlias[imported] = local;
- }
- let isUsedInTemplate = true;
- if (isTS && sfc.template && !sfc.template.src && !sfc.template.lang) {
- isUsedInTemplate = new RegExp(
- // #4274 escape $ since it's a special char in regex
- // (and is the only regex special char that is valid in identifiers)
- `[^\\w$_]${local.replace(/\$/g, '\\$')}[^\\w$_]`).test(resolveTemplateUsageCheckString(sfc));
- }
- userImports[local] = {
- isType,
- imported: imported || 'default',
- source,
- isFromSetup,
- isUsedInTemplate
- };
- }
- function processDefineProps(node) {
- if (!isCallOf(node, DEFINE_PROPS)) {
- return false;
- }
- if (hasDefinePropsCall) {
- error(`duplicate ${DEFINE_PROPS}() call`, node);
- }
- hasDefinePropsCall = true;
- propsRuntimeDecl = node.arguments[0];
- // call has type parameters - infer runtime types from it
- if (node.typeParameters) {
- if (propsRuntimeDecl) {
- error(`${DEFINE_PROPS}() cannot accept both type and non-type arguments ` +
- `at the same time. Use one or the other.`, node);
- }
- propsTypeDeclRaw = node.typeParameters.params[0];
- propsTypeDecl = resolveQualifiedType(propsTypeDeclRaw, node => node.type === 'TSTypeLiteral');
- if (!propsTypeDecl) {
- error(`type argument passed to ${DEFINE_PROPS}() must be a literal type, ` +
- `or a reference to an interface or literal type.`, propsTypeDeclRaw);
- }
- }
- return true;
- }
- function processWithDefaults(node) {
- if (!isCallOf(node, WITH_DEFAULTS)) {
- return false;
- }
- if (processDefineProps(node.arguments[0])) {
- if (propsRuntimeDecl) {
- error(`${WITH_DEFAULTS} can only be used with type-based ` +
- `${DEFINE_PROPS} declaration.`, node);
- }
- propsRuntimeDefaults = node.arguments[1];
- if (!propsRuntimeDefaults ||
- propsRuntimeDefaults.type !== 'ObjectExpression') {
- error(`The 2nd argument of ${WITH_DEFAULTS} must be an object literal.`, propsRuntimeDefaults || node);
- }
- }
- else {
- error(`${WITH_DEFAULTS}' first argument must be a ${DEFINE_PROPS} call.`, node.arguments[0] || node);
- }
- return true;
- }
- function processDefineEmits(node) {
- if (!isCallOf(node, DEFINE_EMITS)) {
- return false;
- }
- if (hasDefineEmitCall) {
- error(`duplicate ${DEFINE_EMITS}() call`, node);
- }
- hasDefineEmitCall = true;
- emitsRuntimeDecl = node.arguments[0];
- if (node.typeParameters) {
- if (emitsRuntimeDecl) {
- error(`${DEFINE_EMITS}() cannot accept both type and non-type arguments ` +
- `at the same time. Use one or the other.`, node);
- }
- emitsTypeDeclRaw = node.typeParameters.params[0];
- emitsTypeDecl = resolveQualifiedType(emitsTypeDeclRaw, node => node.type === 'TSFunctionType' || node.type === 'TSTypeLiteral');
- if (!emitsTypeDecl) {
- error(`type argument passed to ${DEFINE_EMITS}() must be a function type, ` +
- `a literal type with call signatures, or a reference to the above types.`, emitsTypeDeclRaw);
- }
- }
- return true;
- }
- function resolveQualifiedType(node, qualifier) {
- if (qualifier(node)) {
- return node;
- }
- if (node.type === 'TSTypeReference' &&
- node.typeName.type === 'Identifier') {
- const refName = node.typeName.name;
- const isQualifiedType = (node) => {
- if (node.type === 'TSInterfaceDeclaration' &&
- node.id.name === refName) {
- return node.body;
- }
- else if (node.type === 'TSTypeAliasDeclaration' &&
- node.id.name === refName &&
- qualifier(node.typeAnnotation)) {
- return node.typeAnnotation;
- }
- else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
- return isQualifiedType(node.declaration);
- }
- };
- for (const node of scriptSetupAst.body) {
- const qualified = isQualifiedType(node);
- if (qualified) {
- return qualified;
- }
- }
- }
- }
- function processDefineExpose(node) {
- if (isCallOf(node, DEFINE_EXPOSE)) {
- if (hasDefineExposeCall) {
- error(`duplicate ${DEFINE_EXPOSE}() call`, node);
- }
- hasDefineExposeCall = true;
- return true;
- }
- return false;
- }
- function checkInvalidScopeReference(node, method) {
- if (!node)
- return;
- CompilerDOM.walkIdentifiers(node, id => {
- if (setupBindings[id.name]) {
- error(`\`${method}()\` in <script setup> cannot reference locally ` +
- `declared variables because it will be hoisted outside of the ` +
- `setup() function. If your component options requires initialization ` +
- `in the module scope, use a separate normal <script> to export ` +
- `the options instead.`, id);
- }
- });
- }
- /**
- * await foo()
- * -->
- * (([__temp, __restore] = withAsyncContext(() => foo())),__temp=await __temp,__restore(),__temp)
- */
- function processAwait(node, isStatement) {
- s.overwrite(node.start + startOffset, node.argument.start + startOffset, `${isStatement ? `;` : ``}(([__temp,__restore]=${helper(`withAsyncContext`)}(()=>(`);
- s.appendLeft(node.end + startOffset, `))),__temp=await __temp,__restore()${isStatement ? `` : `,__temp`})`);
- }
- /**
- * check defaults. If the default object is an object literal with only
- * static properties, we can directly generate more optimzied default
- * decalrations. Otherwise we will have to fallback to runtime merging.
- */
- function checkStaticDefaults() {
- return (propsRuntimeDefaults &&
- propsRuntimeDefaults.type === 'ObjectExpression' &&
- propsRuntimeDefaults.properties.every(node => (node.type === 'ObjectProperty' && !node.computed) ||
- node.type === 'ObjectMethod'));
- }
- function genRuntimeProps(props) {
- const keys = Object.keys(props);
- if (!keys.length) {
- return ``;
- }
- const hasStaticDefaults = checkStaticDefaults();
- const scriptSetupSource = scriptSetup.content;
- let propsDecls = `{
- ${keys
- .map(key => {
- let defaultString;
- if (hasStaticDefaults) {
- const prop = propsRuntimeDefaults.properties.find((node) => node.key.name === key);
- if (prop) {
- if (prop.type === 'ObjectProperty') {
- // prop has corresponding static default value
- defaultString = `default: ${scriptSetupSource.slice(prop.value.start, prop.value.end)}`;
- }
- else {
- defaultString = `default() ${scriptSetupSource.slice(prop.body.start, prop.body.end)}`;
- }
- }
- }
- {
- const { type, required } = props[key];
- return `${key}: { type: ${toRuntimeTypeString(type)}, required: ${required}${defaultString ? `, ${defaultString}` : ``} }`;
- }
- })
- .join(',\n ')}\n }`;
- if (propsRuntimeDefaults && !hasStaticDefaults) {
- propsDecls = `${helper('mergeDefaults')}(${propsDecls}, ${source.slice(propsRuntimeDefaults.start + startOffset, propsRuntimeDefaults.end + startOffset)})`;
- }
- return `\n props: ${propsDecls},`;
- }
- function genSetupPropsType(node) {
- const scriptSetupSource = scriptSetup.content;
- if (checkStaticDefaults()) {
- // if withDefaults() is used, we need to remove the optional flags
- // on props that have default values
- let res = `{ `;
- const members = node.type === 'TSTypeLiteral' ? node.members : node.body;
- for (const m of members) {
- if ((m.type === 'TSPropertySignature' ||
- m.type === 'TSMethodSignature') &&
- m.typeAnnotation &&
- m.key.type === 'Identifier') {
- if (propsRuntimeDefaults.properties.some((p) => p.key.name === m.key.name)) {
- res +=
- m.key.name +
- (m.type === 'TSMethodSignature' ? '()' : '') +
- scriptSetupSource.slice(m.typeAnnotation.start, m.typeAnnotation.end) +
- ', ';
- }
- else {
- res += scriptSetupSource.slice(m.start, m.end) + `, `;
- }
- }
- }
- return (res.length ? res.slice(0, -2) : res) + ` }`;
- }
- else {
- return scriptSetupSource.slice(node.start, node.end);
- }
- }
- // 1. process normal <script> first if it exists
- let scriptAst;
- if (script) {
- // import dedupe between <script> and <script setup>
- scriptAst = parse(script.content, {
- plugins,
- sourceType: 'module'
- }, scriptStartOffset);
- for (const node of scriptAst.body) {
- if (node.type === 'ImportDeclaration') {
- // record imports for dedupe
- for (const specifier of node.specifiers) {
- const imported = specifier.type === 'ImportSpecifier' &&
- specifier.imported.type === 'Identifier' &&
- specifier.imported.name;
- registerUserImport(node.source.value, specifier.local.name, imported, node.importKind === 'type', false);
- }
- }
- else if (node.type === 'ExportDefaultDeclaration') {
- // export default
- defaultExport = node;
- const start = node.start + scriptStartOffset;
- const end = node.declaration.start + scriptStartOffset;
- s.overwrite(start, end, `const ${defaultTempVar} = `);
- }
- else if (node.type === 'ExportNamedDeclaration' && node.specifiers) {
- const defaultSpecifier = node.specifiers.find(s => s.exported.type === 'Identifier' && s.exported.name === 'default');
- if (defaultSpecifier) {
- defaultExport = node;
- // 1. remove specifier
- if (node.specifiers.length > 1) {
- s.remove(defaultSpecifier.start + scriptStartOffset, defaultSpecifier.end + scriptStartOffset);
- }
- else {
- s.remove(node.start + scriptStartOffset, node.end + scriptStartOffset);
- }
- if (node.source) {
- // export { x as default } from './x'
- // rewrite to `import { x as __default__ } from './x'` and
- // add to top
- s.prepend(`import { ${defaultSpecifier.local.name} as ${defaultTempVar} } from '${node.source.value}'\n`);
- }
- else {
- // export { x as default }
- // rewrite to `const __default__ = x` and move to end
- s.append(`\nconst ${defaultTempVar} = ${defaultSpecifier.local.name}\n`);
- }
- }
- }
- else if ((node.type === 'VariableDeclaration' ||
- node.type === 'FunctionDeclaration' ||
- node.type === 'ClassDeclaration') &&
- !node.declare) {
- walkDeclaration(node, setupBindings, userImportAlias);
- }
- }
- // apply ref transform
- if (enableRefTransform && refTransform.shouldTransform(script.content)) {
- const { rootVars, importedHelpers } = refTransform.transformAST(scriptAst, s, scriptStartOffset);
- refBindings = rootVars;
- for (const h of importedHelpers) {
- helperImports.add(h);
- }
- }
- }
- // 2. parse <script setup> and walk over top level statements
- const scriptSetupAst = parse(scriptSetup.content, {
- plugins: [
- ...plugins,
- // allow top level await but only inside <script setup>
- 'topLevelAwait'
- ],
- sourceType: 'module'
- }, startOffset);
- for (const node of scriptSetupAst.body) {
- const start = node.start + startOffset;
- let end = node.end + startOffset;
- // locate comment
- if (node.trailingComments && node.trailingComments.length > 0) {
- const lastCommentNode = node.trailingComments[node.trailingComments.length - 1];
- end = lastCommentNode.end + startOffset;
- }
- // locate the end of whitespace between this statement and the next
- while (end <= source.length) {
- if (!/\s/.test(source.charAt(end))) {
- break;
- }
- end++;
- }
- // (Dropped) `ref: x` bindings
- if (node.type === 'LabeledStatement' &&
- node.label.name === 'ref' &&
- node.body.type === 'ExpressionStatement') {
- error(`ref sugar using the label syntax was an experimental proposal and ` +
- `has been dropped based on community feedback. Please check out ` +
- `the new proposal at https://github.com/vuejs/rfcs/discussions/369`, node);
- }
- if (node.type === 'ImportDeclaration') {
- // import declarations are moved to top
- s.move(start, end, 0);
- // dedupe imports
- let removed = 0;
- const removeSpecifier = (i) => {
- const removeLeft = i > removed;
- removed++;
- const current = node.specifiers[i];
- const next = node.specifiers[i + 1];
- s.remove(removeLeft
- ? node.specifiers[i - 1].end + startOffset
- : current.start + startOffset, next && !removeLeft
- ? next.start + startOffset
- : current.end + startOffset);
- };
- for (let i = 0; i < node.specifiers.length; i++) {
- const specifier = node.specifiers[i];
- const local = specifier.local.name;
- const imported = specifier.type === 'ImportSpecifier' &&
- specifier.imported.type === 'Identifier' &&
- specifier.imported.name;
- const source = node.source.value;
- const existing = userImports[local];
- if (source === 'vue' &&
- (imported === DEFINE_PROPS ||
- imported === DEFINE_EMITS ||
- imported === DEFINE_EXPOSE)) {
- warnOnce(`\`${imported}\` is a compiler macro and no longer needs to be imported.`);
- removeSpecifier(i);
- }
- else if (existing) {
- if (existing.source === source && existing.imported === imported) {
- // already imported in <script setup>, dedupe
- removeSpecifier(i);
- }
- else {
- error(`different imports aliased to same local name.`, specifier);
- }
- }
- else {
- registerUserImport(source, local, imported, node.importKind === 'type', true);
- }
- }
- if (node.specifiers.length && removed === node.specifiers.length) {
- s.remove(node.start + startOffset, node.end + startOffset);
- }
- }
- if (node.type === 'ExpressionStatement') {
- // process `defineProps` and `defineEmit(s)` calls
- if (processDefineProps(node.expression) ||
- processDefineEmits(node.expression) ||
- processWithDefaults(node.expression)) {
- s.remove(node.start + startOffset, node.end + startOffset);
- }
- else if (processDefineExpose(node.expression)) {
- // defineExpose({}) -> expose({})
- const callee = node.expression.callee;
- s.overwrite(callee.start + startOffset, callee.end + startOffset, 'expose');
- }
- }
- if (node.type === 'VariableDeclaration' && !node.declare) {
- const total = node.declarations.length;
- let left = total;
- for (let i = 0; i < total; i++) {
- const decl = node.declarations[i];
- if (decl.init) {
- // defineProps / defineEmits
- const isDefineProps = processDefineProps(decl.init) || processWithDefaults(decl.init);
- if (isDefineProps) {
- propsIdentifier = scriptSetup.content.slice(decl.id.start, decl.id.end);
- }
- const isDefineEmits = processDefineEmits(decl.init);
- if (isDefineEmits) {
- emitIdentifier = scriptSetup.content.slice(decl.id.start, decl.id.end);
- }
- if (isDefineProps || isDefineEmits) {
- if (left === 1) {
- s.remove(node.start + startOffset, node.end + startOffset);
- }
- else {
- let start = decl.start + startOffset;
- let end = decl.end + startOffset;
- if (i < total - 1) {
- // not the last one, locate the start of the next
- end = node.declarations[i + 1].start + startOffset;
- }
- else {
- // last one, locate the end of the prev
- start = node.declarations[i - 1].end + startOffset;
- }
- s.remove(start, end);
- left--;
- }
- }
- }
- }
- }
- // walk decalrations to record declared bindings
- if ((node.type === 'VariableDeclaration' ||
- node.type === 'FunctionDeclaration' ||
- node.type === 'ClassDeclaration') &&
- !node.declare) {
- walkDeclaration(node, setupBindings, userImportAlias);
- }
- // walk statements & named exports / variable declarations for top level
- // await
- if ((node.type === 'VariableDeclaration' && !node.declare) ||
- node.type.endsWith('Statement')) {
- estreeWalker.walk(node, {
- enter(child, parent) {
- if (CompilerDOM.isFunctionType(child)) {
- this.skip();
- }
- if (child.type === 'AwaitExpression') {
- hasAwait = true;
- processAwait(child, parent.type === 'ExpressionStatement');
- }
- }
- });
- }
- if ((node.type === 'ExportNamedDeclaration' && node.exportKind !== 'type') ||
- node.type === 'ExportAllDeclaration' ||
- node.type === 'ExportDefaultDeclaration') {
- error(`<script setup> cannot contain ES module exports. ` +
- `If you are using a previous version of <script setup>, please ` +
- `consult the updated RFC at https://github.com/vuejs/rfcs/pull/227.`, node);
- }
- if (isTS) {
- // runtime enum
- if (node.type === 'TSEnumDeclaration') {
- registerBinding(setupBindings, node.id, "setup-const" /* SETUP_CONST */);
- }
- // move all Type declarations to outer scope
- if (node.type.startsWith('TS') ||
- (node.type === 'ExportNamedDeclaration' &&
- node.exportKind === 'type') ||
- (node.type === 'VariableDeclaration' && node.declare)) {
- recordType(node, declaredTypes);
- s.move(start, end, 0);
- }
- }
- }
- // 3. Apply ref sugar transform
- if (enableRefTransform && refTransform.shouldTransform(scriptSetup.content)) {
- const { rootVars, importedHelpers } = refTransform.transformAST(scriptSetupAst, s, startOffset, refBindings);
- refBindings = refBindings ? [...refBindings, ...rootVars] : rootVars;
- for (const h of importedHelpers) {
- helperImports.add(h);
- }
- }
- // 4. extract runtime props/emits code from setup context type
- if (propsTypeDecl) {
- extractRuntimeProps(propsTypeDecl, typeDeclaredProps, declaredTypes);
- }
- if (emitsTypeDecl) {
- extractRuntimeEmits(emitsTypeDecl, typeDeclaredEmits);
- }
- // 5. check useOptions args to make sure it doesn't reference setup scope
- // variables
- checkInvalidScopeReference(propsRuntimeDecl, DEFINE_PROPS);
- checkInvalidScopeReference(propsRuntimeDefaults, DEFINE_PROPS);
- checkInvalidScopeReference(emitsRuntimeDecl, DEFINE_PROPS);
- // 6. remove non-script content
- if (script) {
- if (startOffset < scriptStartOffset) {
- // <script setup> before <script>
- s.remove(0, startOffset);
- s.remove(endOffset, scriptStartOffset);
- s.remove(scriptEndOffset, source.length);
- }
- else {
- // <script> before <script setup>
- s.remove(0, scriptStartOffset);
- s.remove(scriptEndOffset, startOffset);
- s.remove(endOffset, source.length);
- }
- }
- else {
- // only <script setup>
- s.remove(0, startOffset);
- s.remove(endOffset, source.length);
- }
- // 7. analyze binding metadata
- if (scriptAst) {
- Object.assign(bindingMetadata, analyzeScriptBindings(scriptAst.body));
- }
- if (propsRuntimeDecl) {
- for (const key of getObjectOrArrayExpressionKeys(propsRuntimeDecl)) {
- bindingMetadata[key] = "props" /* PROPS */;
- }
- }
- for (const key in typeDeclaredProps) {
- bindingMetadata[key] = "props" /* PROPS */;
- }
- for (const [key, { isType, imported, source }] of Object.entries(userImports)) {
- if (isType)
- continue;
- bindingMetadata[key] =
- (imported === 'default' && source.endsWith('.vue')) || source === 'vue'
- ? "setup-const" /* SETUP_CONST */
- : "setup-maybe-ref" /* SETUP_MAYBE_REF */;
- }
- for (const key in setupBindings) {
- bindingMetadata[key] = setupBindings[key];
- }
- // known ref bindings
- if (refBindings) {
- for (const key of refBindings) {
- bindingMetadata[key] = "setup-ref" /* SETUP_REF */;
- }
- }
- // 8. inject `useCssVars` calls
- if (cssVars.length) {
- helperImports.add(CSS_VARS_HELPER);
- helperImports.add('unref');
- s.prependRight(startOffset, `\n${genCssVarsCode(cssVars, bindingMetadata, scopeId, !!options.isProd)}\n`);
- }
- // 9. finalize setup() argument signature
- let args = `__props`;
- if (propsTypeDecl) {
- // mark as any and only cast on assignment
- // since the user defined complex types may be incompatible with the
- // inferred type from generated runtime declarations
- args += `: any`;
- }
- // inject user assignment of props
- // we use a default __props so that template expressions referencing props
- // can use it directly
- if (propsIdentifier) {
- s.prependRight(startOffset, `\nconst ${propsIdentifier} = __props${propsTypeDecl ? ` as ${genSetupPropsType(propsTypeDecl)}` : ``}`);
- }
- // inject temp variables for async context preservation
- if (hasAwait) {
- const any = isTS ? `: any` : ``;
- s.prependRight(startOffset, `\nlet __temp${any}, __restore${any}\n`);
- }
- const destructureElements = hasDefineExposeCall || !options.inlineTemplate ? [`expose`] : [];
- if (emitIdentifier) {
- destructureElements.push(emitIdentifier === `emit` ? `emit` : `emit: ${emitIdentifier}`);
- }
- if (destructureElements.length) {
- args += `, { ${destructureElements.join(', ')} }`;
- if (emitsTypeDecl) {
- args += `: { emit: (${scriptSetup.content.slice(emitsTypeDecl.start, emitsTypeDecl.end)}), expose: any, slots: any, attrs: any }`;
- }
- }
- // 10. generate return statement
- let returned;
- if (options.inlineTemplate) {
- if (sfc.template && !sfc.template.src) {
- if (options.templateOptions && options.templateOptions.ssr) {
- hasInlinedSsrRenderFn = true;
- }
- // inline render function mode - we are going to compile the template and
- // inline it right here
- const { code, ast, preamble, tips, errors } = compileTemplate(Object.assign(Object.assign({ filename, source: sfc.template.content, inMap: sfc.template.map }, options.templateOptions), { id: scopeId, scoped: sfc.styles.some(s => s.scoped), isProd: options.isProd, ssrCssVars: sfc.cssVars, compilerOptions: Object.assign(Object.assign({}, (options.templateOptions &&
- options.templateOptions.compilerOptions)), { inline: true, isTS,
- bindingMetadata }) }));
- if (tips.length) {
- tips.forEach(warnOnce);
- }
- const err = errors[0];
- if (typeof err === 'string') {
- throw new Error(err);
- }
- else if (err) {
- if (err.loc) {
- err.message +=
- `\n\n` +
- sfc.filename +
- '\n' +
- shared.generateCodeFrame(source, err.loc.start.offset, err.loc.end.offset) +
- `\n`;
- }
- throw err;
- }
- if (preamble) {
- s.prepend(preamble);
- }
- // avoid duplicated unref import
- // as this may get injected by the render function preamble OR the
- // css vars codegen
- if (ast && ast.helpers.includes(CompilerDOM.UNREF)) {
- helperImports.delete('unref');
- }
- returned = code;
- }
- else {
- returned = `() => {}`;
- }
- }
- else {
- // return bindings from setup
- const allBindings = Object.assign({}, setupBindings);
- for (const key in userImports) {
- if (!userImports[key].isType && userImports[key].isUsedInTemplate) {
- allBindings[key] = true;
- }
- }
- returned = `{ ${Object.keys(allBindings).join(', ')} }`;
- }
- if (!options.inlineTemplate && !false) {
- // in non-inline mode, the `__isScriptSetup: true` flag is used by
- // componentPublicInstance proxy to allow properties that start with $ or _
- s.appendRight(endOffset, `\nconst __returned__ = ${returned}\n` +
- `Object.defineProperty(__returned__, '__isScriptSetup', { enumerable: false, value: true })\n` +
- `return __returned__` +
- `\n}\n\n`);
- }
- else {
- s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`);
- }
- // 11. finalize default export
- let runtimeOptions = ``;
- if (hasInlinedSsrRenderFn) {
- runtimeOptions += `\n __ssrInlineRender: true,`;
- }
- if (propsRuntimeDecl) {
- runtimeOptions += `\n props: ${scriptSetup.content
- .slice(propsRuntimeDecl.start, propsRuntimeDecl.end)
- .trim()},`;
- }
- else if (propsTypeDecl) {
- runtimeOptions += genRuntimeProps(typeDeclaredProps);
- }
- if (emitsRuntimeDecl) {
- runtimeOptions += `\n emits: ${scriptSetup.content
- .slice(emitsRuntimeDecl.start, emitsRuntimeDecl.end)
- .trim()},`;
- }
- else if (emitsTypeDecl) {
- runtimeOptions += genRuntimeEmits(typeDeclaredEmits);
- }
- // <script setup> components are closed by default. If the user did not
- // explicitly call `defineExpose`, call expose() with no args.
- const exposeCall = hasDefineExposeCall || options.inlineTemplate ? `` : ` expose()\n`;
- if (isTS) {
- // for TS, make sure the exported type is still valid type with
- // correct props information
- // we have to use object spread for types to be merged properly
- // user's TS setting should compile it down to proper targets
- const def = defaultExport ? `\n ...${defaultTempVar},` : ``;
- // wrap setup code with function.
- // export the content of <script setup> as a named export, `setup`.
- // this allows `import { setup } from '*.vue'` for testing purposes.
- if (defaultExport) {
- s.prependLeft(startOffset, `\n${hasAwait ? `async ` : ``}function setup(${args}) {\n`);
- s.append(`\nexport default /*#__PURE__*/${helper(`defineComponent`)}({${def}${runtimeOptions}\n setup})`);
- }
- else {
- s.prependLeft(startOffset, `\nexport default /*#__PURE__*/${helper(`defineComponent`)}({${def}${runtimeOptions}\n ${hasAwait ? `async ` : ``}setup(${args}) {\n${exposeCall}`);
- s.appendRight(endOffset, `})`);
- }
- }
- else {
- if (defaultExport) {
- // can't rely on spread operator in non ts mode
- s.prependLeft(startOffset, `\n${hasAwait ? `async ` : ``}function setup(${args}) {\n`);
- s.append(`\nexport default /*#__PURE__*/ Object.assign(${defaultTempVar}, {${runtimeOptions}\n setup\n})\n`);
- }
- else {
- s.prependLeft(startOffset, `\nexport default {${runtimeOptions}\n ` +
- `${hasAwait ? `async ` : ``}setup(${args}) {\n${exposeCall}`);
- s.appendRight(endOffset, `}`);
- }
- }
- // 12. finalize Vue helper imports
- if (helperImports.size > 0) {
- s.prepend(`import { ${[...helperImports]
- .map(h => `${h} as _${h}`)
- .join(', ')} } from 'vue'\n`);
- }
- s.trim();
- return Object.assign(Object.assign({}, scriptSetup), { bindings: bindingMetadata, content: s.toString(), map: s.generateMap({
- source: filename,
- hires: true,
- includeContent: true
- }), scriptAst: scriptAst === null || scriptAst === void 0 ? void 0 : scriptAst.body, scriptSetupAst: scriptSetupAst === null || scriptSetupAst === void 0 ? void 0 : scriptSetupAst.body });
- }
- function registerBinding(bindings, node, type) {
- bindings[node.name] = type;
- }
- function walkDeclaration(node, bindings, userImportAlias) {
- if (node.type === 'VariableDeclaration') {
- const isConst = node.kind === 'const';
- // export const foo = ...
- for (const { id, init } of node.declarations) {
- const isDefineCall = !!(isConst &&
- isCallOf(init, c => c === DEFINE_PROPS || c === DEFINE_EMITS || c === WITH_DEFAULTS));
- if (id.type === 'Identifier') {
- let bindingType;
- const userReactiveBinding = userImportAlias['reactive'] || 'reactive';
- if (isCallOf(init, userReactiveBinding)) {
- // treat reactive() calls as let since it's meant to be mutable
- bindingType = "setup-let" /* SETUP_LET */;
- }
- else if (
- // if a declaration is a const literal, we can mark it so that
- // the generated render fn code doesn't need to unref() it
- isDefineCall ||
- (isConst && canNeverBeRef(init, userReactiveBinding))) {
- bindingType = "setup-const" /* SETUP_CONST */;
- }
- else if (isConst) {
- if (isCallOf(init, userImportAlias['ref'] || 'ref')) {
- bindingType = "setup-ref" /* SETUP_REF */;
- }
- else {
- bindingType = "setup-maybe-ref" /* SETUP_MAYBE_REF */;
- }
- }
- else {
- bindingType = "setup-let" /* SETUP_LET */;
- }
- registerBinding(bindings, id, bindingType);
- }
- else if (id.type === 'ObjectPattern') {
- walkObjectPattern(id, bindings, isConst, isDefineCall);
- }
- else if (id.type === 'ArrayPattern') {
- walkArrayPattern(id, bindings, isConst, isDefineCall);
- }
- }
- }
- else if (node.type === 'FunctionDeclaration' ||
- node.type === 'ClassDeclaration') {
- // export function foo() {} / export class Foo {}
- // export declarations must be named.
- bindings[node.id.name] = "setup-const" /* SETUP_CONST */;
- }
- }
- function walkObjectPattern(node, bindings, isConst, isDefineCall = false) {
- for (const p of node.properties) {
- if (p.type === 'ObjectProperty') {
- // key can only be Identifier in ObjectPattern
- if (p.key.type === 'Identifier') {
- if (p.key === p.value) {
- // const { x } = ...
- const type = isDefineCall
- ? "setup-const" /* SETUP_CONST */
- : isConst
- ? "setup-maybe-ref" /* SETUP_MAYBE_REF */
- : "setup-let" /* SETUP_LET */;
- registerBinding(bindings, p.key, type);
- }
- else {
- walkPattern(p.value, bindings, isConst, isDefineCall);
- }
- }
- }
- else {
- // ...rest
- // argument can only be identifer when destructuring
- const type = isConst ? "setup-const" /* SETUP_CONST */ : "setup-let" /* SETUP_LET */;
- registerBinding(bindings, p.argument, type);
- }
- }
- }
- function walkArrayPattern(node, bindings, isConst, isDefineCall = false) {
- for (const e of node.elements) {
- e && walkPattern(e, bindings, isConst, isDefineCall);
- }
- }
- function walkPattern(node, bindings, isConst, isDefineCall = false) {
- if (node.type === 'Identifier') {
- const type = isDefineCall
- ? "setup-const" /* SETUP_CONST */
- : isConst
- ? "setup-maybe-ref" /* SETUP_MAYBE_REF */
- : "setup-let" /* SETUP_LET */;
- registerBinding(bindings, node, type);
- }
- else if (node.type === 'RestElement') {
- // argument can only be identifer when destructuring
- const type = isConst ? "setup-const" /* SETUP_CONST */ : "setup-let" /* SETUP_LET */;
- registerBinding(bindings, node.argument, type);
- }
- else if (node.type === 'ObjectPattern') {
- walkObjectPattern(node, bindings, isConst);
- }
- else if (node.type === 'ArrayPattern') {
- walkArrayPattern(node, bindings, isConst);
- }
- else if (node.type === 'AssignmentPattern') {
- if (node.left.type === 'Identifier') {
- const type = isDefineCall
- ? "setup-const" /* SETUP_CONST */
- : isConst
- ? "setup-maybe-ref" /* SETUP_MAYBE_REF */
- : "setup-let" /* SETUP_LET */;
- registerBinding(bindings, node.left, type);
- }
- else {
- walkPattern(node.left, bindings, isConst);
- }
- }
- }
- function recordType(node, declaredTypes) {
- if (node.type === 'TSInterfaceDeclaration') {
- declaredTypes[node.id.name] = [`Object`];
- }
- else if (node.type === 'TSTypeAliasDeclaration') {
- declaredTypes[node.id.name] = inferRuntimeType(node.typeAnnotation, declaredTypes);
- }
- else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
- recordType(node.declaration, declaredTypes);
- }
- }
- function extractRuntimeProps(node, props, declaredTypes) {
- const members = node.type === 'TSTypeLiteral' ? node.members : node.body;
- for (const m of members) {
- if ((m.type === 'TSPropertySignature' || m.type === 'TSMethodSignature') &&
- m.key.type === 'Identifier') {
- let type;
- {
- if (m.type === 'TSMethodSignature') {
- type = ['Function'];
- }
- else if (m.typeAnnotation) {
- type = inferRuntimeType(m.typeAnnotation.typeAnnotation, declaredTypes);
- }
- }
- props[m.key.name] = {
- key: m.key.name,
- required: !m.optional,
- type: type || [`null`]
- };
- }
- }
- }
- function inferRuntimeType(node, declaredTypes) {
- switch (node.type) {
- case 'TSStringKeyword':
- return ['String'];
- case 'TSNumberKeyword':
- return ['Number'];
- case 'TSBooleanKeyword':
- return ['Boolean'];
- case 'TSObjectKeyword':
- return ['Object'];
- case 'TSTypeLiteral':
- // TODO (nice to have) generate runtime property validation
- return ['Object'];
- case 'TSFunctionType':
- return ['Function'];
- case 'TSArrayType':
- case 'TSTupleType':
- // TODO (nice to have) generate runtime element type/length checks
- return ['Array'];
- case 'TSLiteralType':
- switch (node.literal.type) {
- case 'StringLiteral':
- return ['String'];
- case 'BooleanLiteral':
- return ['Boolean'];
- case 'NumericLiteral':
- case 'BigIntLiteral':
- return ['Number'];
- default:
- return [`null`];
- }
- case 'TSTypeReference':
- if (node.typeName.type === 'Identifier') {
- if (declaredTypes[node.typeName.name]) {
- return declaredTypes[node.typeName.name];
- }
- switch (node.typeName.name) {
- case 'Array':
- case 'Function':
- case 'Object':
- case 'Set':
- case 'Map':
- case 'WeakSet':
- case 'WeakMap':
- return [node.typeName.name];
- case 'Record':
- case 'Partial':
- case 'Readonly':
- case 'Pick':
- case 'Omit':
- case 'Exclude':
- case 'Extract':
- case 'Required':
- case 'InstanceType':
- return ['Object'];
- }
- }
- return [`null`];
- case 'TSParenthesizedType':
- return inferRuntimeType(node.typeAnnotation, declaredTypes);
- case 'TSUnionType':
- return [
- ...new Set([].concat(...node.types.map(t => inferRuntimeType(t, declaredTypes))))
- ];
- case 'TSIntersectionType':
- return ['Object'];
- default:
- return [`null`]; // no runtime check
- }
- }
- function toRuntimeTypeString(types) {
- return types.length > 1 ? `[${types.join(', ')}]` : types[0];
- }
- function extractRuntimeEmits(node, emits) {
- if (node.type === 'TSTypeLiteral' || node.type === 'TSInterfaceBody') {
- const members = node.type === 'TSTypeLiteral' ? node.members : node.body;
- for (let t of members) {
- if (t.type === 'TSCallSignatureDeclaration') {
- extractEventNames(t.parameters[0], emits);
- }
- }
- return;
- }
- else {
- extractEventNames(node.parameters[0], emits);
- }
- }
- function extractEventNames(eventName, emits) {
- if (eventName.type === 'Identifier' &&
- eventName.typeAnnotation &&
- eventName.typeAnnotation.type === 'TSTypeAnnotation') {
- const typeNode = eventName.typeAnnotation.typeAnnotation;
- if (typeNode.type === 'TSLiteralType') {
- if (typeNode.literal.type !== 'UnaryExpression') {
- emits.add(String(typeNode.literal.value));
- }
- }
- else if (typeNode.type === 'TSUnionType') {
- for (const t of typeNode.types) {
- if (t.type === 'TSLiteralType' &&
- t.literal.type !== 'UnaryExpression') {
- emits.add(String(t.literal.value));
- }
- }
- }
- }
- }
- function genRuntimeEmits(emits) {
- return emits.size
- ? `\n emits: [${Array.from(emits)
- .map(p => JSON.stringify(p))
- .join(', ')}],`
- : ``;
- }
- function isCallOf(node, test) {
- return !!(node &&
- node.type === 'CallExpression' &&
- node.callee.type === 'Identifier' &&
- (typeof test === 'string'
- ? node.callee.name === test
- : test(node.callee.name)));
- }
- function canNeverBeRef(node, userReactiveImport) {
- if (isCallOf(node, userReactiveImport)) {
- return true;
- }
- switch (node.type) {
- case 'UnaryExpression':
- case 'BinaryExpression':
- case 'ArrayExpression':
- case 'ObjectExpression':
- case 'FunctionExpression':
- case 'ArrowFunctionExpression':
- case 'UpdateExpression':
- case 'ClassExpression':
- case 'TaggedTemplateExpression':
- return true;
- case 'SequenceExpression':
- return canNeverBeRef(node.expressions[node.expressions.length - 1], userReactiveImport);
- default:
- if (node.type.endsWith('Literal')) {
- return true;
- }
- return false;
- }
- }
- /**
- * Analyze bindings in normal `<script>`
- * Note that `compileScriptSetup` already analyzes bindings as part of its
- * compilation process so this should only be used on single `<script>` SFCs.
- */
- function analyzeScriptBindings(ast) {
- for (const node of ast) {
- if (node.type === 'ExportDefaultDeclaration' &&
- node.declaration.type === 'ObjectExpression') {
- return analyzeBindingsFromOptions(node.declaration);
- }
- }
- return {};
- }
- function analyzeBindingsFromOptions(node) {
- const bindings = {};
- // #3270, #3275
- // mark non-script-setup so we don't resolve components/directives from these
- Object.defineProperty(bindings, '__isScriptSetup', {
- enumerable: false,
- value: false
- });
- for (const property of node.properties) {
- if (property.type === 'ObjectProperty' &&
- !property.computed &&
- property.key.type === 'Identifier') {
- // props
- if (property.key.name === 'props') {
- // props: ['foo']
- // props: { foo: ... }
- for (const key of getObjectOrArrayExpressionKeys(property.value)) {
- bindings[key] = "props" /* PROPS */;
- }
- }
- // inject
- else if (property.key.name === 'inject') {
- // inject: ['foo']
- // inject: { foo: {} }
- for (const key of getObjectOrArrayExpressionKeys(property.value)) {
- bindings[key] = "options" /* OPTIONS */;
- }
- }
- // computed & methods
- else if (property.value.type === 'ObjectExpression' &&
- (property.key.name === 'computed' || property.key.name === 'methods')) {
- // methods: { foo() {} }
- // computed: { foo() {} }
- for (const key of getObjectExpressionKeys(property.value)) {
- bindings[key] = "options" /* OPTIONS */;
- }
- }
- }
- // setup & data
- else if (property.type === 'ObjectMethod' &&
- property.key.type === 'Identifier' &&
- (property.key.name === 'setup' || property.key.name === 'data')) {
- for (const bodyItem of property.body.body) {
- // setup() {
- // return {
- // foo: null
- // }
- // }
- if (bodyItem.type === 'ReturnStatement' &&
- bodyItem.argument &&
- bodyItem.argument.type === 'ObjectExpression') {
- for (const key of getObjectExpressionKeys(bodyItem.argument)) {
- bindings[key] =
- property.key.name === 'setup'
- ? "setup-maybe-ref" /* SETUP_MAYBE_REF */
- : "data" /* DATA */;
- }
- }
- }
- }
- }
- return bindings;
- }
- function getObjectExpressionKeys(node) {
- const keys = [];
- for (const prop of node.properties) {
- if ((prop.type === 'ObjectProperty' || prop.type === 'ObjectMethod') &&
- !prop.computed) {
- if (prop.key.type === 'Identifier') {
- keys.push(prop.key.name);
- }
- else if (prop.key.type === 'StringLiteral') {
- keys.push(prop.key.value);
- }
- }
- }
- return keys;
- }
- function getArrayExpressionKeys(node) {
- const keys = [];
- for (const element of node.elements) {
- if (element && element.type === 'StringLiteral') {
- keys.push(element.value);
- }
- }
- return keys;
- }
- function getObjectOrArrayExpressionKeys(value) {
- if (value.type === 'ArrayExpression') {
- return getArrayExpressionKeys(value);
- }
- if (value.type === 'ObjectExpression') {
- return getObjectExpressionKeys(value);
- }
- return [];
- }
- const templateUsageCheckCache = createCache();
- function resolveTemplateUsageCheckString(sfc) {
- const { content, ast } = sfc.template;
- const cached = templateUsageCheckCache.get(content);
- if (cached) {
- return cached;
- }
- let code = '';
- CompilerDOM.transform(CompilerDOM.createRoot([ast]), {
- nodeTransforms: [
- node => {
- if (node.type === 1 /* ELEMENT */) {
- if (!CompilerDOM.parserOptions.isNativeTag(node.tag) &&
- !CompilerDOM.parserOptions.isBuiltInComponent(node.tag)) {
- code += `,${shared.camelize(node.tag)},${shared.capitalize(shared.camelize(node.tag))}`;
- }
- for (let i = 0; i < node.props.length; i++) {
- const prop = node.props[i];
- if (prop.type === 7 /* DIRECTIVE */) {
- if (!isBuiltInDir(prop.name)) {
- code += `,v${shared.capitalize(shared.camelize(prop.name))}`;
- }
- if (prop.exp) {
- code += `,${stripStrings(prop.exp.content)}`;
- }
- }
- }
- }
- else if (node.type === 5 /* INTERPOLATION */) {
- code += `,${stripStrings(node.content.content)}`;
- }
- }
- ]
- });
- code += ';';
- templateUsageCheckCache.set(content, code);
- return code;
- }
- function stripStrings(exp) {
- return exp
- .replace(/'[^']+'|"[^"]+"/g, '')
- .replace(/`[^`]+`/g, stripTemplateString);
- }
- function stripTemplateString(str) {
- const interpMatch = str.match(/\${[^}]+}/g);
- if (interpMatch) {
- return interpMatch.map(m => m.slice(2, -1)).join(',');
- }
- return '';
- }
- exports.extractIdentifiers = compilerCore.extractIdentifiers;
- exports.generateCodeFrame = compilerCore.generateCodeFrame;
- exports.isInDestructureAssignment = compilerCore.isInDestructureAssignment;
- exports.isStaticProperty = compilerCore.isStaticProperty;
- exports.walkIdentifiers = compilerCore.walkIdentifiers;
- exports.MagicString = MagicString__default;
- exports.babelParse = parser.parse;
- exports.walk = estreeWalker.walk;
- exports.shouldTransformRef = refTransform.shouldTransform;
- exports.transformRef = refTransform.transform;
- exports.transformRefAST = refTransform.transformAST;
- exports.compileScript = compileScript;
- exports.compileStyle = compileStyle;
- exports.compileStyleAsync = compileStyleAsync;
- exports.compileTemplate = compileTemplate;
- exports.parse = parse;
- exports.rewriteDefault = rewriteDefault;
|