--- /dev/null
+# @vue/compiler-sfc
+
+> Lower level utilities for compiling Vue single file components
+
+This package contains lower level utilities that you can use if you are writing a plugin / transform for a bundler or module system that compiles Vue single file components into JavaScript. It is used in [vue-loader](https://github.com/vuejs/vue-loader).
+
+The API surface is intentionally minimal - the goal is to reuse as much as possible while being as flexible as possible.
+
+## Why isn't `@vue/compiler-dom` a peerDependency?
+
+Since this package is more often used as a low-level utility, it is usually a transitive dependency in an actual Vue project. It is therefore the responsibility of the higher-level package (e.g. `vue-loader`) to inject `@vue/compiler-dom` via options when calling the `compileTemplate` methods.
+
+Not listing it as a peer depedency also allows tooling authors to use a custom template compiler (built on top of `@vue/compiler-core`) instead of `@vue/compiler-dom`, without having to include it just to fullfil the peer dep requirement.
+
+## API
+
+TODO
--- /dev/null
+{
+ "extends": "../../api-extractor.json",
+ "mainEntryPointFilePath": "./dist/packages/<unscopedPackageName>/src/index.d.ts",
+ "dtsRollup": {
+ "untrimmedFilePath": "./dist/<unscopedPackageName>.d.ts"
+ }
+}
\ No newline at end of file
--- /dev/null
+{
+ "name": "@vue/compiler-sfc",
+ "version": "3.0.0-alpha.1",
+ "description": "@vue/compiler-sfc",
+ "main": "dist/compiler-sfc.cjs.js",
+ "files": [
+ "dist"
+ ],
+ "types": "dist/compiler-sfc.d.ts",
+ "buildOptions": {
+ "prod": false,
+ "formats": [
+ "cjs"
+ ]
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/vuejs/vue.git"
+ },
+ "keywords": [
+ "vue"
+ ],
+ "author": "Evan You",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/vuejs/vue/issues"
+ },
+ "homepage": "https://github.com/vuejs/vue/tree/dev/packages/compiler-sfc#readme",
+ "dependencies": {
+ "@vue/compiler-core": "3.0.0-alpha.1",
+ "consolidate": "^0.15.1",
+ "hash-sum": "^2.0.0",
+ "lru-cache": "^5.1.1",
+ "merge-source-map": "^1.1.0",
+ "postcss": "^7.0.21",
+ "postcss-selector-parser": "^6.0.2",
+ "source-map": "^0.7.3"
+ }
+}
--- /dev/null
+// const postcss = require('postcss')
+import postcss, { ProcessOptions, LazyResult, Result, ResultMap } from 'postcss'
+import trimPlugin from './stylePluginTrim'
+import scopedPlugin from './stylePluginScoped'
+import {
+ processors,
+ StylePreprocessor,
+ StylePreprocessorResults
+} from './stylePreprocessors'
+
+export interface StyleCompileOptions {
+ source: string
+ filename: string
+ id: string
+ map?: object
+ scoped?: boolean
+ trim?: boolean
+ preprocessLang?: string
+ preprocessOptions?: any
+ postcssOptions?: any
+ postcssPlugins?: any[]
+}
+
+export interface AsyncStyleCompileOptions extends StyleCompileOptions {
+ isAsync?: boolean
+}
+
+export interface StyleCompileResults {
+ code: string
+ map: object | void
+ rawResult: LazyResult | Result | undefined
+ errors: string[]
+}
+
+export function compileStyle(
+ options: StyleCompileOptions
+): StyleCompileResults {
+ return doCompileStyle({ ...options, isAsync: false }) as StyleCompileResults
+}
+
+export function compileStyleAsync(
+ options: StyleCompileOptions
+): Promise<StyleCompileResults> {
+ return doCompileStyle({ ...options, isAsync: true }) as Promise<
+ StyleCompileResults
+ >
+}
+
+export function doCompileStyle(
+ options: AsyncStyleCompileOptions
+): StyleCompileResults | Promise<StyleCompileResults> {
+ const {
+ filename,
+ id,
+ scoped = true,
+ trim = true,
+ preprocessLang,
+ postcssOptions,
+ postcssPlugins
+ } = options
+ const preprocessor = preprocessLang && processors[preprocessLang]
+ const preProcessedSource = preprocessor && preprocess(options, preprocessor)
+ const map = preProcessedSource ? preProcessedSource.map : options.map
+ const source = preProcessedSource ? preProcessedSource.code : options.source
+
+ const plugins = (postcssPlugins || []).slice()
+ if (trim) {
+ plugins.push(trimPlugin())
+ }
+ if (scoped) {
+ plugins.push(scopedPlugin(id))
+ }
+
+ const postCSSOptions: ProcessOptions = {
+ ...postcssOptions,
+ to: filename,
+ from: filename
+ }
+ if (map) {
+ postCSSOptions.map = {
+ inline: false,
+ annotation: false,
+ prev: map
+ }
+ }
+
+ let result: LazyResult | undefined
+ let code: string | undefined
+ let outMap: ResultMap | undefined
+
+ const errors: any[] = []
+ if (preProcessedSource && preProcessedSource.errors.length) {
+ errors.push(...preProcessedSource.errors)
+ }
+
+ try {
+ result = postcss(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,
+ rawResult: result
+ }))
+ .catch(error => ({
+ code: '',
+ map: undefined,
+ errors: [...errors, error.message],
+ rawResult: undefined
+ }))
+ }
+
+ // 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
+ }
+}
+
+function preprocess(
+ options: StyleCompileOptions,
+ preprocessor: StylePreprocessor
+): StylePreprocessorResults {
+ return preprocessor.render(
+ options.source,
+ options.map,
+ Object.assign(
+ {
+ filename: options.filename
+ },
+ options.preprocessOptions
+ )
+ )
+}
--- /dev/null
+export function compileTemplate() {
+ // TODO
+}
--- /dev/null
+// API
+export { parse } from './parse'
+export { compileTemplate } from './compileTemplate'
+export { compileStyle, compileStyleAsync } from './compileStyle'
+
+// Types
+export {
+ SFCParseOptions,
+ SFCDescriptor,
+ SFCBlock,
+ SFCTemplateBlock,
+ SFCScriptBlock,
+ SFCStyleBlock
+} from './parse'
+
+export { StyleCompileOptions, StyleCompileResults } from './compileStyle'
--- /dev/null
+import {
+ parse as baseParse,
+ TextModes,
+ NodeTypes,
+ TextNode,
+ ElementNode,
+ SourceLocation
+} from '@vue/compiler-core'
+import { RawSourceMap } from 'source-map'
+
+export interface SFCParseOptions {
+ needMap?: boolean
+ filename?: string
+ sourceRoot?: string
+}
+
+export interface SFCBlock {
+ type: string
+ content: string
+ attrs: Record<string, string | true>
+ loc: SourceLocation
+ map?: RawSourceMap
+ lang?: string
+ src?: string
+}
+
+export interface SFCTemplateBlock extends SFCBlock {
+ type: 'template'
+ functional?: boolean
+}
+
+export interface SFCScriptBlock extends SFCBlock {
+ type: 'script'
+}
+
+export interface SFCStyleBlock extends SFCBlock {
+ type: 'style'
+ scoped?: boolean
+ module?: string | boolean
+}
+
+export interface SFCDescriptor {
+ filename: string
+ template: SFCTemplateBlock | null
+ script: SFCScriptBlock | null
+ styles: SFCStyleBlock[]
+ customBlocks: SFCBlock[]
+}
+
+export function parse(
+ source: string,
+ {
+ needMap = true,
+ filename = 'component.vue',
+ sourceRoot = ''
+ }: SFCParseOptions = {}
+): SFCDescriptor {
+ // TODO check cache
+
+ const sfc: SFCDescriptor = {
+ filename,
+ template: null,
+ script: null,
+ styles: [],
+ customBlocks: []
+ }
+ const ast = baseParse(source, {
+ isNativeTag: () => true,
+ getTextMode: () => TextModes.RAWTEXT
+ })
+
+ ast.children.forEach(node => {
+ if (node.type !== NodeTypes.ELEMENT) {
+ return
+ }
+ switch (node.tag) {
+ case 'template':
+ if (!sfc.template) {
+ sfc.template = createBlock(node) as SFCTemplateBlock
+ } else {
+ // TODO warn duplicate template
+ }
+ break
+ case 'script':
+ if (!sfc.script) {
+ sfc.script = createBlock(node) as SFCScriptBlock
+ } else {
+ // TODO warn duplicate script
+ }
+ break
+ case 'style':
+ sfc.styles.push(createBlock(node) as SFCStyleBlock)
+ break
+ default:
+ sfc.customBlocks.push(createBlock(node))
+ break
+ }
+ })
+
+ if (needMap) {
+ // TODO source map
+ }
+ // TODO set cache
+
+ return sfc
+}
+
+function createBlock(node: ElementNode): SFCBlock {
+ const type = node.tag
+ const text = node.children[0] as TextNode
+ const attrs: Record<string, string | true> = {}
+ const block: SFCBlock = {
+ type,
+ content: text.content,
+ loc: text.loc,
+ attrs
+ }
+ node.props.forEach(p => {
+ if (p.type === NodeTypes.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 as SFCStyleBlock).scoped = true
+ } else if (p.name === 'module') {
+ ;(block as SFCStyleBlock).module = attrs[p.name]
+ }
+ } else if (type === 'template' && p.name === 'functional') {
+ ;(block as SFCTemplateBlock).functional = true
+ }
+ }
+ })
+ return block
+}
--- /dev/null
+declare module 'merge-source-map' {
+ export default function merge(oldMap: object, newMap: object): object
+}
--- /dev/null
+import postcss, { Root } from 'postcss'
+import selectorParser from 'postcss-selector-parser'
+
+export default postcss.plugin('add-id', (options: any) => (root: Root) => {
+ const id: string = options
+ const keyframes = Object.create(null)
+
+ root.each(function rewriteSelector(node: any) {
+ if (!node.selector) {
+ // handle media queries
+ if (node.type === 'atrule') {
+ if (node.name === 'media' || node.name === 'supports') {
+ node.each(rewriteSelector)
+ } else if (/-?keyframes$/.test(node.name)) {
+ // register keyframes
+ keyframes[node.params] = node.params = node.params + '-' + id
+ }
+ }
+ return
+ }
+ node.selector = selectorParser((selectors: any) => {
+ selectors.each((selector: any) => {
+ let node: any = null
+
+ // find the last child node to insert attribute selector
+ selector.each((n: any) => {
+ // ">>>" combinator
+ // and /deep/ alias for >>>, since >>> doesn't work in SASS
+ if (
+ n.type === 'combinator' &&
+ (n.value === '>>>' || n.value === '/deep/')
+ ) {
+ n.value = ' '
+ n.spaces.before = n.spaces.after = ''
+ return false
+ }
+
+ // in newer versions of sass, /deep/ support is also dropped, so add a ::v-deep alias
+ if (n.type === 'pseudo' && n.value === '::v-deep') {
+ n.value = n.spaces.before = n.spaces.after = ''
+ 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 = ''
+ }
+
+ selector.insertAfter(
+ node,
+ selectorParser.attribute({
+ attribute: id,
+ value: id,
+ raws: {}
+ })
+ )
+ })
+ }).processSync(node.selector)
+ })
+
+ // 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.
+ if (Object.keys(keyframes).length) {
+ root.walkDecls(decl => {
+ // individual animation-name declaration
+ if (/^(-\w+-)?animation-name$/.test(decl.prop)) {
+ decl.value = decl.value
+ .split(',')
+ .map(v => keyframes[v.trim()] || v.trim())
+ .join(',')
+ }
+ // shorthand
+ if (/^(-\w+-)?animation$/.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(',')
+ }
+ })
+ }
+})
--- /dev/null
+import postcss, { Root } from 'postcss'
+
+export default postcss.plugin('trim', () => (css: Root) => {
+ css.walk(({ type, raws }) => {
+ if (type === 'rule' || type === 'atrule') {
+ if (raws.before) raws.before = '\n'
+ if (raws.after) raws.after = '\n'
+ }
+ })
+})
--- /dev/null
+import merge from 'merge-source-map'
+
+export interface StylePreprocessor {
+ render(source: string, map?: object, options?: any): StylePreprocessorResults
+}
+
+export interface StylePreprocessorResults {
+ code: string
+ map?: object
+ errors: Array<Error>
+}
+
+// .scss/.sass processor
+const scss: StylePreprocessor = {
+ render(source, map, options) {
+ const nodeSass = require('sass')
+ const finalOptions = Object.assign({}, options, {
+ data: source,
+ file: options.filename,
+ outFile: options.filename,
+ sourceMap: !!map
+ })
+
+ try {
+ const result = nodeSass.renderSync(finalOptions)
+
+ if (map) {
+ return {
+ code: result.css.toString(),
+ map: merge(map, JSON.parse(result.map.toString())),
+ errors: []
+ }
+ }
+
+ return { code: result.css.toString(), errors: [] }
+ } catch (e) {
+ return { code: '', errors: [e] }
+ }
+ }
+}
+
+const sass: StylePreprocessor = {
+ render(source, map, options) {
+ return scss.render(
+ source,
+ map,
+ Object.assign({}, options, { indentedSyntax: true })
+ )
+ }
+}
+
+// .less
+const less: StylePreprocessor = {
+ render(source, map, options) {
+ const nodeLess = require('less')
+
+ let result: any
+ let error: Error | null = null
+ nodeLess.render(
+ source,
+ Object.assign({}, options, { syncImport: true }),
+ (err: Error | null, output: any) => {
+ error = err
+ result = output
+ }
+ )
+
+ if (error) return { code: '', errors: [error] }
+
+ if (map) {
+ return {
+ code: result.css.toString(),
+ map: merge(map, result.map),
+ errors: []
+ }
+ }
+
+ return { code: result.css.toString(), errors: [] }
+ }
+}
+
+// .styl
+const styl: StylePreprocessor = {
+ render(source, map, options) {
+ const nodeStylus = require('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()
+ if (map) {
+ return {
+ code: result,
+ map: merge(map, ref.sourcemap),
+ errors: []
+ }
+ }
+
+ return { code: result, errors: [] }
+ } catch (e) {
+ return { code: '', errors: [e] }
+ }
+ }
+}
+
+export const processors: Record<string, StylePreprocessor> = {
+ less,
+ sass,
+ scss,
+ styl,
+ stylus: styl
+}
--- /dev/null
+import { NodeTransform } from '@vue/compiler-core'
+
+export const transformAssetUrl: NodeTransform = () => {
+ // TODO
+}
--- /dev/null
+import { NodeTransform } from '@vue/compiler-core'
+
+export const transformSrcset: NodeTransform = () => {
+ // TODO
+}
--- /dev/null
+export interface Attr {
+ name: string
+ value: string
+}
+
+export interface ASTNode {
+ tag: string
+ attrs: Attr[]
+}
+
+import { UrlWithStringQuery, parse as uriParse } from 'url'
+
+// TODO use imports instead
+export function urlToRequire(url: string): string {
+ const returnValue = `"${url}"`
+ // same logic as in transform-require.js
+ const firstChar = url.charAt(0)
+ if (firstChar === '.' || firstChar === '~' || firstChar === '@') {
+ if (firstChar === '~') {
+ const secondChar = url.charAt(1)
+ url = url.slice(secondChar === '/' ? 2 : 1)
+ }
+
+ const uriParts = parseUriParts(url)
+
+ if (!uriParts.hash) {
+ return `require("${url}")`
+ } else {
+ // support uri fragment case by excluding it from
+ // the require and instead appending it as string;
+ // assuming that the path part is sufficient according to
+ // the above caseing(t.i. no protocol-auth-host parts expected)
+ return `require("${uriParts.path}") + "${uriParts.hash}"`
+ }
+ }
+ return returnValue
+}
+
+/**
+ * vuejs/component-compiler-utils#22 Support uri fragment in transformed require
+ * @param urlString an url as a string
+ */
+function parseUriParts(urlString: string): UrlWithStringQuery {
+ // initialize return value
+ const returnValue: UrlWithStringQuery = uriParse('')
+ if (urlString) {
+ // A TypeError is thrown if urlString is not a string
+ // @see https://nodejs.org/api/url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost
+ if ('string' === typeof urlString) {
+ // check is an uri
+ return uriParse(urlString) // take apart the uri
+ }
+ }
+ return returnValue
+}
if (process.env.NODE_ENV === 'production') {
packageFormats.forEach(format => {
- if (format === 'cjs') {
+ if (format === 'cjs' && packageOptions.prod !== false) {
packageConfigs.push(createProductionConfig(format))
}
if (format === 'global' || format === 'esm-browser') {
// during a single build.
hasTSChecked = true
- const externals = Object.keys(aliasOptions).filter(p => p !== '@vue/shared')
+ const externals = Object.keys(aliasOptions)
+ .concat(Object.keys(pkg.dependencies || []))
+ .filter(p => p !== '@vue/shared')
return {
input: resolve(`src/index.ts`),
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635"
integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==
+bluebird@^3.1.1:
+ version "3.7.1"
+ resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de"
+ integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==
+
bluebird@^3.5.1:
version "3.5.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.2.tgz#1be0908e054a751754549c270489c1505d4ab15a"
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
+consolidate@^0.15.1:
+ version "0.15.1"
+ resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7"
+ integrity sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==
+ dependencies:
+ bluebird "^3.1.1"
+
conventional-changelog-angular@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.3.tgz#299fdd43df5a1f095283ac16aeedfb0a682ecab0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
+cssesc@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
+ integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+
cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
version "0.3.4"
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.4.tgz#8cd52e8a3acfd68d3aed38ee0a640177d2f9d797"
dependencies:
function-bind "^1.1.1"
+hash-sum@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a"
+ integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==
+
hosted-git-info@^2.1.4, hosted-git-info@^2.6.0:
version "2.7.1"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289"
integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=
+indexes-of@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
+ integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc=
+
infer-owner@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
trim-newlines "^2.0.0"
yargs-parser "^10.0.0"
+merge-source-map@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646"
+ integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==
+ dependencies:
+ source-map "^0.6.1"
+
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
+postcss-selector-parser@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c"
+ integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==
+ dependencies:
+ cssesc "^3.0.0"
+ indexes-of "^1.0.1"
+ uniq "^1.0.1"
+
+postcss@^7.0.21:
+ version "7.0.21"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.21.tgz#06bb07824c19c2021c5d056d5b10c35b989f7e17"
+ integrity sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==
+ dependencies:
+ chalk "^2.4.2"
+ source-map "^0.6.1"
+ supports-color "^6.1.0"
+
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
is-extendable "^0.1.1"
set-value "^0.4.3"
+uniq@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
+ integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=
+
unique-filename@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230"