next-yak 1.1.4 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -183,23 +183,47 @@ async function parseFile(loader, filePath) {
183
183
  const exports = await parseExports(await sourceContents, isTSX);
184
184
  const mixins = parseMixins(await tranformedSource);
185
185
  await Promise.all(
186
- Object.entries(mixins).map(async ([name, mixin]) => {
187
- mixins[name] = {
188
- type: "mixin",
189
- value: await resolveCrossFileConstant(
190
- loader,
191
- import_path.default.dirname(filePath),
192
- mixin.value
193
- )
194
- };
186
+ Object.entries(mixins).map(async ([name, { value, nameParts }]) => {
187
+ const resolvedValue = await resolveCrossFileConstant(
188
+ loader,
189
+ import_path.default.dirname(filePath),
190
+ value
191
+ );
192
+ if (nameParts.length === 1) {
193
+ exports[name] = { type: "mixin", value: resolvedValue };
194
+ } else {
195
+ let exportEntry = exports[nameParts[0]];
196
+ if (!exportEntry) {
197
+ exportEntry = { type: "record", value: {} };
198
+ exports[nameParts[0]] = exportEntry;
199
+ } else if (exportEntry.type !== "record") {
200
+ throw new Error(
201
+ `Error parsing file ${filePath}: ${nameParts[0]} is not a record`
202
+ );
203
+ }
204
+ let current = exportEntry.value;
205
+ for (let i = 1; i < nameParts.length - 1; i++) {
206
+ let next = current[nameParts[i]];
207
+ if (!next) {
208
+ next = { type: "record", value: {} };
209
+ current[nameParts[i]] = next;
210
+ } else if (next.type !== "record") {
211
+ throw new Error(
212
+ `Error parsing file ${filePath}: ${nameParts[i]} is not a record`
213
+ );
214
+ }
215
+ current = next.value;
216
+ }
217
+ current[nameParts[nameParts.length - 1]] = {
218
+ type: "mixin",
219
+ value: resolvedValue
220
+ };
221
+ }
195
222
  })
196
223
  );
197
224
  return {
198
225
  type: "regular",
199
- exports: {
200
- ...exports,
201
- ...mixins
202
- },
226
+ exports,
203
227
  filePath
204
228
  };
205
229
  } catch (error) {
@@ -282,7 +306,11 @@ function parseMixins(sourceContents) {
282
306
  const position = comment.indexOf("\n");
283
307
  const name = comment.slice(0, position);
284
308
  const value = comment.slice(position + 1);
285
- mixins[name] = { type: "mixin", value };
309
+ mixins[name] = {
310
+ type: "mixin",
311
+ value,
312
+ nameParts: name.split(":").map((part) => decodeURIComponent(part))
313
+ };
286
314
  }
287
315
  return mixins;
288
316
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../loaders/css-loader.ts","../../loaders/lib/resolveCrossFileSelectors.ts"],"sourcesContent":["import type { LoaderContext } from \"webpack\";\nimport { resolveCrossFileConstant } from \"./lib/resolveCrossFileSelectors.js\";\nimport { relative } from \"path\";\nimport type { YakConfigOptions } from \"../withYak/index.js\";\n\n/**\n * Transform typescript to css\n *\n * This loader takes the cached result from the yak tsloader\n * and extracts the css from the generated comments\n */\nexport default async function cssExtractLoader(\n this: LoaderContext<YakConfigOptions>,\n // Instead of the source code, we receive the extracted css\n // from the ts-loader transformation\n _code: string,\n sourceMap: string | undefined,\n): Promise<string | void> {\n const callback = this.async();\n // Load the module from the original typescript request (without !=! and the query)\n return this.loadModule(this.resourcePath, (err, source) => {\n if (err) {\n return callback(err);\n }\n const { experiments } = this.getOptions();\n const debugLog = createDebugLogger(this, experiments?.debug);\n\n debugLog(\"ts\", source);\n const css = extractCss(source);\n debugLog(\"css\", css);\n\n return resolveCrossFileConstant(this, this.context, css).then((result) => {\n debugLog(\"css resolved\", css);\n return callback(null, result, sourceMap);\n }, callback);\n });\n}\n\nfunction extractCss(code: string): string {\n const codeParts = code.split(\"/*YAK Extracted CSS:\\n\");\n let result = \"\";\n for (let i = 1; i < codeParts.length; i++) {\n const codeUntilEnd = codeParts[i].split(\"*/\")[0];\n result += codeUntilEnd;\n }\n return result;\n}\n\nfunction createDebugLogger(\n loaderContext: LoaderContext<YakConfigOptions>,\n debugOptions: Required<YakConfigOptions>[\"experiments\"][\"debug\"],\n) {\n if (\n !debugOptions ||\n (debugOptions !== true &&\n debugOptions.filter &&\n !debugOptions.filter(loaderContext.resourcePath))\n ) {\n return () => {};\n }\n const debugType = debugOptions === true ? \"ts\" : debugOptions.type;\n return (messageType: \"ts\" | \"css\" | \"css resolved\", message: string) => {\n if (messageType === debugType || debugType === \"all\") {\n console.log(\n \"🐮 Yak\",\n messageType,\n \"\\n\",\n loaderContext._compiler\n ? relative(\n loaderContext._compiler.context,\n loaderContext.resourcePath,\n )\n : loaderContext.resourcePath,\n \"\\n\\n\",\n message,\n );\n }\n };\n}\n","import path from \"path\";\nimport babel from \"@babel/core\";\n// @ts-expect-error - this is used by babel directly so we ignore that it is not typed\nimport babelPlugin from \"@babel/plugin-syntax-typescript\";\nimport type { Compilation, LoaderContext } from \"webpack\";\nimport { getCssModuleLocalIdent } from \"next/dist/build/webpack/config/blocks/css/loaders/getCssModuleLocalIdent.js\";\n\nconst yakCssImportRegex =\n // Make mixin and selector non optional once we dropped support for the babel plugin\n /--yak-css-import\\:\\s*url\\(\"([^\"]+)\",?(|mixin|selector)\\)(;?)/g;\n\nconst compilationCache = new WeakMap<\n Compilation,\n Map<string, Promise<ParsedFile>>\n>();\n\n/**\n * Resolves cross-file selectors in css files\n *\n * e.g.:\n * theme.ts:\n * ```ts\n * export const colors = {\n * primary: \"#ff0000\",\n * secondary: \"#00ff00\",\n * };\n * ```\n *\n * styles.ts:\n * ```ts\n * import { colors } from \"./theme\";\n * export const button = css`\n * background-color: ${colors.primary};\n * `;\n */\nexport async function resolveCrossFileConstant(\n loader: LoaderContext<{}>,\n pathContext: string,\n css: string,\n): Promise<string> {\n // Search for --yak-css-import: url(\"path/to/module\") in the css\n const matches = [...css.matchAll(yakCssImportRegex)].map((match) => {\n const [fullMatch, encodedArguments, importKind, semicolon] = match;\n const [moduleSpecifier, ...specifier] = encodedArguments\n .split(\":\")\n .map((entry) => decodeURIComponent(entry));\n return {\n encodedArguments,\n moduleSpecifier,\n specifier,\n importKind,\n semicolon,\n position: match.index!,\n size: fullMatch.length,\n };\n });\n if (matches.length === 0) return css;\n\n try {\n // Resolve all imports concurrently\n const exportCache = new Map<string, Promise<ResolvedExport>>();\n const resolvedValues = await Promise.all(\n matches.map(({ moduleSpecifier, specifier, encodedArguments }) => {\n // The cache prevents resolving the same specifier multiple times\n // e.g.:\n // const a = css`\n // color: ${colors.primary};\n // border-color: ${colors.primary};\n // `;\n const resolvedFromCache = exportCache.get(encodedArguments);\n const resolvedValue =\n resolvedFromCache ||\n parseModule(loader, moduleSpecifier, pathContext).then(\n (parsedModule) =>\n resolveModuleSpecifierRecursively(\n loader,\n parsedModule,\n specifier,\n ),\n );\n if (!resolvedFromCache) {\n exportCache.set(encodedArguments, resolvedValue);\n }\n return resolvedValue;\n }),\n );\n\n // Replace the imports with the resolved values\n let result = css;\n for (let i = matches.length - 1; i >= 0; i--) {\n const { position, size, importKind, specifier, semicolon } = matches[i];\n const resolved = resolvedValues[i];\n\n if (importKind === \"selector\") {\n if (resolved.type === \"mixin\") {\n throw new Error(\n `Found mixin but expected a selector - did you forget a semicolon after \\`${specifier.join(\n \".\",\n )}\\`?`,\n );\n }\n }\n\n const replacement =\n resolved.type === \"styled-component\"\n ? `:global(.${getCssModuleLocalIdent(\n {\n rootContext: loader.rootContext,\n resourcePath: resolved.from,\n },\n null,\n resolved.name,\n {},\n )})`\n : resolved.value +\n // resolved.value can be of two different types:\n // - mixin:\n // ${mixinName};\n // - constant:\n // color: ${value};\n // For mixins the semicolon is already included in the value\n // but for constants it has to be added manually\n ([\"}\", \";\"].includes(String(resolved.value).trimEnd().slice(-1))\n ? \"\"\n : semicolon);\n\n result =\n result.slice(0, position) +\n String(replacement) +\n result.slice(position + size);\n }\n\n return result;\n } catch (error) {\n throw new Error(\n `Error resolving cross-file selectors: ${\n (error as Error).message\n }\\nFile: ${loader.resourcePath}`,\n );\n }\n}\n\n/**\n * Resolves a module specifier to a parsed file\n *\n * e.g.:\n * ```\n * parseModule(loader, \"./theme\", \"/path/to/styles.ts\")\n * // -> { type: 'regular', secondary: { type: 'constant', value: '#00ff00' } } }, filePath: '/path/to/theme.ts' }\n * ```\n */\nasync function parseModule(\n loader: LoaderContext<{}>,\n moduleSpecifier: string,\n context: string,\n): Promise<ParsedFile> {\n const compilation = loader._compilation;\n if (!compilation) {\n throw new Error(\"Webpack compilation object not available\");\n }\n let cache = compilationCache.get(compilation);\n if (!cache) {\n cache = new Map();\n compilationCache.set(compilation, cache);\n }\n // The cache key is valid for the entire project so it can be reused\n // for different source files\n const cacheKey = path.resolve(context, moduleSpecifier);\n let filePromise = cache.get(cacheKey);\n if (!filePromise) {\n filePromise = (async () => {\n const resolved = await new Promise<string>((resolve, reject) => {\n loader.resolve(context, moduleSpecifier, (err, result) => {\n if (err) return reject(err);\n if (!result)\n return reject(new Error(`Could not resolve ${moduleSpecifier}`));\n resolve(result);\n });\n });\n return parseFile(loader, resolved);\n })();\n cache.set(cacheKey, filePromise);\n }\n // on file change, invalidate the cache\n loader.addDependency((await filePromise).filePath);\n return filePromise;\n}\n\nasync function parseFile(\n loader: LoaderContext<{}>,\n filePath: string,\n): Promise<ParsedFile> {\n const isYak =\n filePath.endsWith(\".yak.ts\") ||\n filePath.endsWith(\".yak.tsx\") ||\n filePath.endsWith(\".yak.js\") ||\n filePath.endsWith(\".yak.jsx\");\n const isTSX = filePath.endsWith(\".tsx\");\n\n try {\n if (isYak) {\n const module: Record<string, unknown> =\n await loader.importModule(filePath);\n const mappedModule = Object.fromEntries(\n Object.entries(module).map(([key, value]): [string, ParsedExport] => {\n if (typeof value === \"string\" || typeof value === \"number\") {\n return [key, { type: \"constant\" as const, value }];\n } else if (\n value &&\n (typeof value === \"object\" || Array.isArray(value))\n ) {\n return [key, { type: \"record\" as const, value }];\n } else {\n return [key, { type: \"unsupported\" as const }];\n }\n }),\n );\n return { type: \"yak\", exports: mappedModule, filePath };\n }\n const sourceContents = new Promise<string>((resolve, reject) =>\n loader.fs.readFile(filePath, \"utf-8\", (err, result) => {\n if (err) return reject(err);\n resolve(result || \"\");\n }),\n );\n\n const tranformedSource = new Promise<string>((resolve, reject) => {\n loader.loadModule(filePath, (err, source) => {\n if (err) return reject(err);\n resolve(source || \"\");\n });\n });\n\n const exports = await parseExports(await sourceContents, isTSX);\n const mixins = parseMixins(await tranformedSource);\n\n // Recursively resolve cross-file constants in mixins\n // e.g. cross file mixins inside a cross file mixin\n // or a cross file selector inside a cross file mixin\n await Promise.all(\n Object.entries(mixins).map(async ([name, mixin]) => {\n mixins[name] = {\n type: \"mixin\",\n value: await resolveCrossFileConstant(\n loader,\n path.dirname(filePath),\n mixin.value,\n ),\n };\n }),\n );\n\n return {\n type: \"regular\",\n exports: {\n ...exports,\n ...mixins,\n },\n filePath,\n };\n } catch (error) {\n throw new Error(\n `Error parsing file ${filePath}: ${(error as Error).message}`,\n );\n }\n}\n\nasync function parseExports(\n sourceContents: string,\n isTSX: boolean,\n): Promise<Record<string, ParsedExport>> {\n let exports: Record<string, ParsedExport> = {};\n\n try {\n babel.transformSync(sourceContents, {\n configFile: false,\n plugins: [\n [babelPlugin, { isTSX }],\n [\n (): babel.PluginObj => ({\n visitor: {\n ExportNamedDeclaration({ node }) {\n if (node.source) {\n node.specifiers.forEach((specifier) => {\n if (\n specifier.type === \"ExportSpecifier\" &&\n specifier.exported.type === \"Identifier\" &&\n specifier.local.type === \"Identifier\"\n ) {\n exports[specifier.exported.name] = {\n type: \"re-export\",\n from: node.source!.value,\n imported: specifier.local.name,\n };\n }\n });\n } else if (node.declaration?.type === \"VariableDeclaration\") {\n node.declaration.declarations.forEach((declaration) => {\n if (\n declaration.id.type === \"Identifier\" &&\n declaration.init\n ) {\n exports[declaration.id.name] = parseExportValueExpression(\n declaration.init,\n );\n }\n });\n }\n },\n ExportDeclaration({ node }) {\n if (\"specifiers\" in node && node.source) {\n const { specifiers, source } = node;\n specifiers.forEach((specifier) => {\n // export * as color from \"./colors\";\n if (\n specifier.type === \"ExportNamespaceSpecifier\" &&\n specifier.exported.type === \"Identifier\"\n ) {\n exports[specifier.exported.name] = {\n type: \"star-export\",\n from: [source.value],\n };\n }\n });\n }\n },\n ExportAllDeclaration({ node }) {\n if (Object.keys(exports).length === 0) {\n exports[\"*\"] ||= {\n type: \"star-export\",\n from: [],\n };\n if (exports[\"*\"].type !== \"star-export\") {\n throw new Error(\"Invalid star export state\");\n }\n exports[\"*\"].from.push(node.source.value);\n }\n },\n },\n }),\n ],\n ],\n });\n\n return exports;\n } catch (error) {\n throw new Error(`Error parsing exports: ${(error as Error).message}`);\n }\n}\n\nfunction parseMixins(\n sourceContents: string,\n): Record<string, { type: \"mixin\"; value: string }> {\n // Mixins are always in the following format:\n // /*YAK EXPORTED MIXIN:name\n // css\n // */\n const mixinParts = sourceContents.split(\"/*YAK EXPORTED MIXIN:\");\n let mixins: Record<string, { type: \"mixin\"; value: string }> = {};\n for (let i = 1; i < mixinParts.length; i++) {\n const [comment] = mixinParts[i].split(\"*/\", 1);\n const position = comment.indexOf(\"\\n\");\n const name = comment.slice(0, position);\n const value = comment.slice(position + 1);\n mixins[name] = { type: \"mixin\", value };\n }\n return mixins;\n}\n\n/**\n * Unpacks a TSAsExpression to its expression value\n */\nfunction unpackTSAsExpression(\n node: babel.types.TSAsExpression | babel.types.Expression,\n): babel.types.Expression {\n if (node.type === \"TSAsExpression\") {\n return unpackTSAsExpression(node.expression);\n }\n return node;\n}\n\nfunction parseExportValueExpression(\n node: babel.types.Expression,\n): ParsedExport {\n // ignores `as` casts so it doesn't interfere with the ast node type detection\n const expression = unpackTSAsExpression(node);\n if (\n expression.type === \"CallExpression\" ||\n expression.type === \"TaggedTemplateExpression\"\n ) {\n return { type: \"styled-component\" };\n } else if (\n expression.type === \"StringLiteral\" ||\n expression.type === \"NumericLiteral\"\n ) {\n return { type: \"constant\", value: expression.value };\n } else if (\n expression.type === \"TemplateLiteral\" &&\n expression.quasis.length === 1\n ) {\n return { type: \"constant\", value: expression.quasis[0].value.raw };\n } else if (expression.type === \"ObjectExpression\") {\n return { type: \"record\", value: parseObjectExpression(expression) };\n }\n return { type: \"unsupported\" };\n}\n\nfunction parseObjectExpression(\n node: babel.types.ObjectExpression,\n): Record<string, any> {\n let result: Record<string, any> = {};\n for (const property of node.properties) {\n if (\n property.type === \"ObjectProperty\" &&\n property.key.type === \"Identifier\"\n ) {\n const key = property.key.name;\n result[key] = parseExportValueExpression(\n property.value as babel.types.Expression,\n );\n }\n }\n return result;\n}\n\n/**\n * Follows a specifier recursively until it finds its constant value\n * for example here it follows \"colors.primary\"\n *\n * ```\n * resolveModuleSpecifierRecursively(loader, \"@/theme\", [\"colors\", \"primary\"], \"colors:primary\")`\n * // -> { type: 'constant', value: '#ff0000' }\n * ```\n *\n * example structure:\n *\n * styles.ts:\n * ```\n * import { colors } from \"@/theme\";\n * export const button = css`color: ${colors.primary}`;\n * ```\n *\n * theme.ts:\n * ```\n * export { colors } from \"./colors\";\n * ```\n *\n * colors.ts:\n * ```\n * export const colors = { primary: \"#ff0000\" };\n * ```\n *\n */\nasync function resolveModuleSpecifierRecursively(\n loader: LoaderContext<{}>,\n module: ParsedFile,\n specifier: string[],\n): Promise<ResolvedExport> {\n try {\n const exportName = specifier[0];\n let exportValue = module.exports[exportName];\n // Follow star exports if there is only a single one\n // and the export does not exist in the current module\n if (exportValue === undefined) {\n const starExport = module.exports[\"*\"];\n if (starExport?.type === \"star-export\") {\n if (starExport.from.length > 1) {\n throw new Error(\n `Could not resolve ${specifier.join(\".\")} in module ${\n module.filePath\n } - Multiple star exports are not supported for performance reasons`,\n );\n }\n exportValue = {\n type: \"re-export\" as const,\n from: starExport.from[0],\n imported: exportName,\n };\n } else {\n throw new Error(\n `Could not resolve \"${specifier.join(\".\")}\" in module ${\n module.filePath\n }`,\n );\n }\n }\n // Follow reexport\n // e.g. export { colors as primaryColors } from \"./colors\";\n if (exportValue.type === \"re-export\") {\n const importedModule = await parseModule(\n loader,\n exportValue.from,\n path.dirname(module.filePath),\n );\n return resolveModuleSpecifierRecursively(loader, importedModule, [\n exportValue.imported,\n ...specifier.slice(1),\n ]);\n }\n // Namespace export\n // e.g. export * as colors from \"./colors\";\n else if (exportValue.type === \"star-export\") {\n const importedModule = await parseModule(\n loader,\n exportValue.from[0],\n path.dirname(module.filePath),\n );\n return resolveModuleSpecifierRecursively(\n loader,\n importedModule,\n specifier.slice(1),\n );\n }\n\n if (exportValue.type === \"styled-component\") {\n return {\n type: \"styled-component\",\n from: module.filePath,\n name: specifier[specifier.length - 1],\n };\n } else if (exportValue.type === \"constant\") {\n return { type: \"constant\", value: exportValue.value };\n } else if (exportValue.type === \"record\") {\n let current: any = exportValue.value;\n let depth = 0;\n /// Drill down the specifier e.g. colors.primary\n do {\n if (typeof current === \"string\" || typeof current === \"number\") {\n return {\n type: \"constant\" as const,\n value: current,\n };\n } else if (\n !current ||\n (typeof current !== \"object\" && !Array.isArray(current))\n ) {\n throw new Error(\n `Error unpacking Record/Array \"${exportName}\".\\nKey \"${\n specifier[depth]\n }\" was of type \"${typeof current}\" but only String and Number are supported`,\n );\n }\n depth++;\n // mixins in .yak files are wrapped inside an object with a __yak key\n if (depth === specifier.length && \"__yak\" in current) {\n return { type: \"mixin\", value: current[\"__yak\"] };\n } else if (depth === specifier.length && \"value\" in current) {\n return { type: \"constant\", value: current[\"value\"] };\n } else {\n current = current[specifier[depth]];\n }\n } while (current);\n if (specifier[depth] === undefined) {\n throw new Error(\n `Error unpacking Record/Array - could not extract \\`${specifier\n .slice(0, depth)\n .join(\".\")}\\` is not a string or number`,\n );\n }\n throw new Error(\n `Error unpacking Record/Array - could not extract \\`${\n specifier[depth]\n }\\` from \\`${specifier.slice(0, depth).join(\".\")}\\``,\n );\n } else if (exportValue.type === \"mixin\") {\n return { type: \"mixin\", value: exportValue.value };\n }\n throw new Error(\n `Error unpacking Record/Array - unexpected exportValue \"${\n exportValue.type\n }\" for specifier \"${specifier.join(\".\")}\"`,\n );\n } catch (error) {\n throw new Error(\n `Error resolving from module ${module.filePath}: ${\n (error as Error).message\n }`,\n );\n }\n}\n\ntype ParsedFile =\n | { type: \"regular\"; exports: Record<string, ParsedExport>; filePath: string }\n | { type: \"yak\"; exports: Record<string, ParsedExport>; filePath: string };\n\ntype ParsedExport =\n | { type: \"styled-component\" }\n | { type: \"mixin\"; value: string }\n | { type: \"constant\"; value: string | number }\n | { type: \"record\"; value: {} }\n | { type: \"unsupported\" }\n | { type: \"re-export\"; from: string; imported: string }\n | { type: \"star-export\"; from: string[] };\n\ntype ResolvedExport =\n | { type: \"styled-component\"; from: string; name: string }\n | { type: \"mixin\"; value: string | number }\n | { type: \"constant\"; value: string | number };\n"],"mappings":"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","names":["path","module","babel","babelPlugin","import_path"]}
1
+ {"version":3,"sources":["../../loaders/css-loader.ts","../../loaders/lib/resolveCrossFileSelectors.ts"],"sourcesContent":["import type { LoaderContext } from \"webpack\";\nimport { resolveCrossFileConstant } from \"./lib/resolveCrossFileSelectors.js\";\nimport { relative } from \"path\";\nimport type { YakConfigOptions } from \"../withYak/index.js\";\n\n/**\n * Transform typescript to css\n *\n * This loader takes the cached result from the yak tsloader\n * and extracts the css from the generated comments\n */\nexport default async function cssExtractLoader(\n this: LoaderContext<YakConfigOptions>,\n // Instead of the source code, we receive the extracted css\n // from the ts-loader transformation\n _code: string,\n sourceMap: string | undefined,\n): Promise<string | void> {\n const callback = this.async();\n // Load the module from the original typescript request (without !=! and the query)\n return this.loadModule(this.resourcePath, (err, source) => {\n if (err) {\n return callback(err);\n }\n const { experiments } = this.getOptions();\n const debugLog = createDebugLogger(this, experiments?.debug);\n\n debugLog(\"ts\", source);\n const css = extractCss(source);\n debugLog(\"css\", css);\n\n return resolveCrossFileConstant(this, this.context, css).then((result) => {\n debugLog(\"css resolved\", css);\n return callback(null, result, sourceMap);\n }, callback);\n });\n}\n\nfunction extractCss(code: string): string {\n const codeParts = code.split(\"/*YAK Extracted CSS:\\n\");\n let result = \"\";\n for (let i = 1; i < codeParts.length; i++) {\n const codeUntilEnd = codeParts[i].split(\"*/\")[0];\n result += codeUntilEnd;\n }\n return result;\n}\n\nfunction createDebugLogger(\n loaderContext: LoaderContext<YakConfigOptions>,\n debugOptions: Required<YakConfigOptions>[\"experiments\"][\"debug\"],\n) {\n if (\n !debugOptions ||\n (debugOptions !== true &&\n debugOptions.filter &&\n !debugOptions.filter(loaderContext.resourcePath))\n ) {\n return () => {};\n }\n const debugType = debugOptions === true ? \"ts\" : debugOptions.type;\n return (messageType: \"ts\" | \"css\" | \"css resolved\", message: string) => {\n if (messageType === debugType || debugType === \"all\") {\n console.log(\n \"🐮 Yak\",\n messageType,\n \"\\n\",\n loaderContext._compiler\n ? relative(\n loaderContext._compiler.context,\n loaderContext.resourcePath,\n )\n : loaderContext.resourcePath,\n \"\\n\\n\",\n message,\n );\n }\n };\n}\n","import path from \"path\";\nimport babel from \"@babel/core\";\n// @ts-expect-error - this is used by babel directly so we ignore that it is not typed\nimport babelPlugin from \"@babel/plugin-syntax-typescript\";\nimport type { Compilation, LoaderContext } from \"webpack\";\nimport { getCssModuleLocalIdent } from \"next/dist/build/webpack/config/blocks/css/loaders/getCssModuleLocalIdent.js\";\n\nconst yakCssImportRegex =\n // Make mixin and selector non optional once we dropped support for the babel plugin\n /--yak-css-import\\:\\s*url\\(\"([^\"]+)\",?(|mixin|selector)\\)(;?)/g;\n\nconst compilationCache = new WeakMap<\n Compilation,\n Map<string, Promise<ParsedFile>>\n>();\n\n/**\n * Resolves cross-file selectors in css files\n *\n * e.g.:\n * theme.ts:\n * ```ts\n * export const colors = {\n * primary: \"#ff0000\",\n * secondary: \"#00ff00\",\n * };\n * ```\n *\n * styles.ts:\n * ```ts\n * import { colors } from \"./theme\";\n * export const button = css`\n * background-color: ${colors.primary};\n * `;\n */\nexport async function resolveCrossFileConstant(\n loader: LoaderContext<{}>,\n pathContext: string,\n css: string,\n): Promise<string> {\n // Search for --yak-css-import: url(\"path/to/module\") in the css\n const matches = [...css.matchAll(yakCssImportRegex)].map((match) => {\n const [fullMatch, encodedArguments, importKind, semicolon] = match;\n const [moduleSpecifier, ...specifier] = encodedArguments\n .split(\":\")\n .map((entry) => decodeURIComponent(entry));\n return {\n encodedArguments,\n moduleSpecifier,\n specifier,\n importKind,\n semicolon,\n position: match.index!,\n size: fullMatch.length,\n };\n });\n if (matches.length === 0) return css;\n\n try {\n // Resolve all imports concurrently\n const exportCache = new Map<string, Promise<ResolvedExport>>();\n const resolvedValues = await Promise.all(\n matches.map(({ moduleSpecifier, specifier, encodedArguments }) => {\n // The cache prevents resolving the same specifier multiple times\n // e.g.:\n // const a = css`\n // color: ${colors.primary};\n // border-color: ${colors.primary};\n // `;\n const resolvedFromCache = exportCache.get(encodedArguments);\n const resolvedValue =\n resolvedFromCache ||\n parseModule(loader, moduleSpecifier, pathContext).then(\n (parsedModule) =>\n resolveModuleSpecifierRecursively(\n loader,\n parsedModule,\n specifier,\n ),\n );\n if (!resolvedFromCache) {\n exportCache.set(encodedArguments, resolvedValue);\n }\n return resolvedValue;\n }),\n );\n\n // Replace the imports with the resolved values\n let result = css;\n for (let i = matches.length - 1; i >= 0; i--) {\n const { position, size, importKind, specifier, semicolon } = matches[i];\n const resolved = resolvedValues[i];\n\n if (importKind === \"selector\") {\n if (resolved.type === \"mixin\") {\n throw new Error(\n `Found mixin but expected a selector - did you forget a semicolon after \\`${specifier.join(\n \".\",\n )}\\`?`,\n );\n }\n }\n\n const replacement =\n resolved.type === \"styled-component\"\n ? `:global(.${getCssModuleLocalIdent(\n {\n rootContext: loader.rootContext,\n resourcePath: resolved.from,\n },\n null,\n resolved.name,\n {},\n )})`\n : resolved.value +\n // resolved.value can be of two different types:\n // - mixin:\n // ${mixinName};\n // - constant:\n // color: ${value};\n // For mixins the semicolon is already included in the value\n // but for constants it has to be added manually\n ([\"}\", \";\"].includes(String(resolved.value).trimEnd().slice(-1))\n ? \"\"\n : semicolon);\n\n result =\n result.slice(0, position) +\n String(replacement) +\n result.slice(position + size);\n }\n\n return result;\n } catch (error) {\n throw new Error(\n `Error resolving cross-file selectors: ${\n (error as Error).message\n }\\nFile: ${loader.resourcePath}`,\n );\n }\n}\n\n/**\n * Resolves a module specifier to a parsed file\n *\n * e.g.:\n * ```\n * parseModule(loader, \"./theme\", \"/path/to/styles.ts\")\n * // -> { type: 'regular', secondary: { type: 'constant', value: '#00ff00' } } }, filePath: '/path/to/theme.ts' }\n * ```\n */\nasync function parseModule(\n loader: LoaderContext<{}>,\n moduleSpecifier: string,\n context: string,\n): Promise<ParsedFile> {\n const compilation = loader._compilation;\n if (!compilation) {\n throw new Error(\"Webpack compilation object not available\");\n }\n let cache = compilationCache.get(compilation);\n if (!cache) {\n cache = new Map();\n compilationCache.set(compilation, cache);\n }\n // The cache key is valid for the entire project so it can be reused\n // for different source files\n const cacheKey = path.resolve(context, moduleSpecifier);\n let filePromise = cache.get(cacheKey);\n if (!filePromise) {\n filePromise = (async () => {\n const resolved = await new Promise<string>((resolve, reject) => {\n loader.resolve(context, moduleSpecifier, (err, result) => {\n if (err) return reject(err);\n if (!result)\n return reject(new Error(`Could not resolve ${moduleSpecifier}`));\n resolve(result);\n });\n });\n return parseFile(loader, resolved);\n })();\n cache.set(cacheKey, filePromise);\n }\n // on file change, invalidate the cache\n loader.addDependency((await filePromise).filePath);\n return filePromise;\n}\n\nasync function parseFile(\n loader: LoaderContext<{}>,\n filePath: string,\n): Promise<ParsedFile> {\n const isYak =\n filePath.endsWith(\".yak.ts\") ||\n filePath.endsWith(\".yak.tsx\") ||\n filePath.endsWith(\".yak.js\") ||\n filePath.endsWith(\".yak.jsx\");\n const isTSX = filePath.endsWith(\".tsx\");\n\n try {\n if (isYak) {\n const module: Record<string, unknown> =\n await loader.importModule(filePath);\n const mappedModule = Object.fromEntries(\n Object.entries(module).map(([key, value]): [string, ParsedExport] => {\n if (typeof value === \"string\" || typeof value === \"number\") {\n return [key, { type: \"constant\" as const, value }];\n } else if (\n value &&\n (typeof value === \"object\" || Array.isArray(value))\n ) {\n return [key, { type: \"record\" as const, value }];\n } else {\n return [key, { type: \"unsupported\" as const }];\n }\n }),\n );\n return { type: \"yak\", exports: mappedModule, filePath };\n }\n const sourceContents = new Promise<string>((resolve, reject) =>\n loader.fs.readFile(filePath, \"utf-8\", (err, result) => {\n if (err) return reject(err);\n resolve(result || \"\");\n }),\n );\n\n const tranformedSource = new Promise<string>((resolve, reject) => {\n loader.loadModule(filePath, (err, source) => {\n if (err) return reject(err);\n resolve(source || \"\");\n });\n });\n\n const exports = await parseExports(await sourceContents, isTSX);\n const mixins = parseMixins(await tranformedSource);\n\n // Recursively resolve cross-file constants in mixins\n // e.g. cross file mixins inside a cross file mixin\n // or a cross file selector inside a cross file mixin\n await Promise.all(\n Object.entries(mixins).map(async ([name, { value, nameParts }]) => {\n const resolvedValue = await resolveCrossFileConstant(\n loader,\n path.dirname(filePath),\n value,\n );\n if (nameParts.length === 1) {\n exports[name] = { type: \"mixin\", value: resolvedValue };\n } else {\n let exportEntry: undefined | ParsedExport = exports[nameParts[0]];\n if (!exportEntry) {\n exportEntry = { type: \"record\", value: {} };\n exports[nameParts[0]] = exportEntry;\n } else if (exportEntry.type !== \"record\") {\n throw new Error(\n `Error parsing file ${filePath}: ${nameParts[0]} is not a record`,\n );\n }\n let current = exportEntry.value as Record<any, ParsedExport>;\n for (let i = 1; i < nameParts.length - 1; i++) {\n let next = current[nameParts[i]];\n if (!next) {\n next = { type: \"record\", value: {} };\n current[nameParts[i]] = next;\n } else if (next.type !== \"record\") {\n throw new Error(\n `Error parsing file ${filePath}: ${nameParts[i]} is not a record`,\n );\n }\n current = next.value;\n }\n current[nameParts[nameParts.length - 1]] = {\n type: \"mixin\",\n value: resolvedValue,\n };\n }\n }),\n );\n\n return {\n type: \"regular\",\n exports,\n filePath,\n };\n } catch (error) {\n throw new Error(\n `Error parsing file ${filePath}: ${(error as Error).message}`,\n );\n }\n}\n\nasync function parseExports(\n sourceContents: string,\n isTSX: boolean,\n): Promise<Record<string, ParsedExport>> {\n let exports: Record<string, ParsedExport> = {};\n\n try {\n babel.transformSync(sourceContents, {\n configFile: false,\n plugins: [\n [babelPlugin, { isTSX }],\n [\n (): babel.PluginObj => ({\n visitor: {\n ExportNamedDeclaration({ node }) {\n if (node.source) {\n node.specifiers.forEach((specifier) => {\n if (\n specifier.type === \"ExportSpecifier\" &&\n specifier.exported.type === \"Identifier\" &&\n specifier.local.type === \"Identifier\"\n ) {\n exports[specifier.exported.name] = {\n type: \"re-export\",\n from: node.source!.value,\n imported: specifier.local.name,\n };\n }\n });\n } else if (node.declaration?.type === \"VariableDeclaration\") {\n node.declaration.declarations.forEach((declaration) => {\n if (\n declaration.id.type === \"Identifier\" &&\n declaration.init\n ) {\n exports[declaration.id.name] = parseExportValueExpression(\n declaration.init,\n );\n }\n });\n }\n },\n ExportDeclaration({ node }) {\n if (\"specifiers\" in node && node.source) {\n const { specifiers, source } = node;\n specifiers.forEach((specifier) => {\n // export * as color from \"./colors\";\n if (\n specifier.type === \"ExportNamespaceSpecifier\" &&\n specifier.exported.type === \"Identifier\"\n ) {\n exports[specifier.exported.name] = {\n type: \"star-export\",\n from: [source.value],\n };\n }\n });\n }\n },\n ExportAllDeclaration({ node }) {\n if (Object.keys(exports).length === 0) {\n exports[\"*\"] ||= {\n type: \"star-export\",\n from: [],\n };\n if (exports[\"*\"].type !== \"star-export\") {\n throw new Error(\"Invalid star export state\");\n }\n exports[\"*\"].from.push(node.source.value);\n }\n },\n },\n }),\n ],\n ],\n });\n\n return exports;\n } catch (error) {\n throw new Error(`Error parsing exports: ${(error as Error).message}`);\n }\n}\n\nfunction parseMixins(\n sourceContents: string,\n): Record<string, { type: \"mixin\"; value: string; nameParts: string[] }> {\n // Mixins are always in the following format:\n // /*YAK EXPORTED MIXIN:fancy:aspectRatio:16:9\n // css\n // */\n const mixinParts = sourceContents.split(\"/*YAK EXPORTED MIXIN:\");\n let mixins: Record<\n string,\n { type: \"mixin\"; value: string; nameParts: string[] }\n > = {};\n\n for (let i = 1; i < mixinParts.length; i++) {\n const [comment] = mixinParts[i].split(\"*/\", 1);\n const position = comment.indexOf(\"\\n\");\n const name = comment.slice(0, position);\n const value = comment.slice(position + 1);\n mixins[name] = {\n type: \"mixin\",\n value,\n nameParts: name.split(\":\").map((part) => decodeURIComponent(part)),\n };\n }\n return mixins;\n}\n\n/**\n * Unpacks a TSAsExpression to its expression value\n */\nfunction unpackTSAsExpression(\n node: babel.types.TSAsExpression | babel.types.Expression,\n): babel.types.Expression {\n if (node.type === \"TSAsExpression\") {\n return unpackTSAsExpression(node.expression);\n }\n return node;\n}\n\nfunction parseExportValueExpression(\n node: babel.types.Expression,\n): ParsedExport {\n // ignores `as` casts so it doesn't interfere with the ast node type detection\n const expression = unpackTSAsExpression(node);\n if (\n expression.type === \"CallExpression\" ||\n expression.type === \"TaggedTemplateExpression\"\n ) {\n return { type: \"styled-component\" };\n } else if (\n expression.type === \"StringLiteral\" ||\n expression.type === \"NumericLiteral\"\n ) {\n return { type: \"constant\", value: expression.value };\n } else if (\n expression.type === \"TemplateLiteral\" &&\n expression.quasis.length === 1\n ) {\n return { type: \"constant\", value: expression.quasis[0].value.raw };\n } else if (expression.type === \"ObjectExpression\") {\n return { type: \"record\", value: parseObjectExpression(expression) };\n }\n return { type: \"unsupported\" };\n}\n\nfunction parseObjectExpression(\n node: babel.types.ObjectExpression,\n): Record<string, ParsedExport> {\n let result: Record<string, ParsedExport> = {};\n for (const property of node.properties) {\n if (\n property.type === \"ObjectProperty\" &&\n property.key.type === \"Identifier\"\n ) {\n const key = property.key.name;\n result[key] = parseExportValueExpression(\n property.value as babel.types.Expression,\n );\n }\n }\n return result;\n}\n\n/**\n * Follows a specifier recursively until it finds its constant value\n * for example here it follows \"colors.primary\"\n *\n * ```\n * resolveModuleSpecifierRecursively(loader, \"@/theme\", [\"colors\", \"primary\"], \"colors:primary\")`\n * // -> { type: 'constant', value: '#ff0000' }\n * ```\n *\n * example structure:\n *\n * styles.ts:\n * ```\n * import { colors } from \"@/theme\";\n * export const button = css`color: ${colors.primary}`;\n * ```\n *\n * theme.ts:\n * ```\n * export { colors } from \"./colors\";\n * ```\n *\n * colors.ts:\n * ```\n * export const colors = { primary: \"#ff0000\" };\n * ```\n *\n */\nasync function resolveModuleSpecifierRecursively(\n loader: LoaderContext<{}>,\n module: ParsedFile,\n specifier: string[],\n): Promise<ResolvedExport> {\n try {\n const exportName = specifier[0];\n let exportValue = module.exports[exportName];\n // Follow star exports if there is only a single one\n // and the export does not exist in the current module\n if (exportValue === undefined) {\n const starExport = module.exports[\"*\"];\n if (starExport?.type === \"star-export\") {\n if (starExport.from.length > 1) {\n throw new Error(\n `Could not resolve ${specifier.join(\".\")} in module ${\n module.filePath\n } - Multiple star exports are not supported for performance reasons`,\n );\n }\n exportValue = {\n type: \"re-export\" as const,\n from: starExport.from[0],\n imported: exportName,\n };\n } else {\n throw new Error(\n `Could not resolve \"${specifier.join(\".\")}\" in module ${\n module.filePath\n }`,\n );\n }\n }\n // Follow reexport\n // e.g. export { colors as primaryColors } from \"./colors\";\n if (exportValue.type === \"re-export\") {\n const importedModule = await parseModule(\n loader,\n exportValue.from,\n path.dirname(module.filePath),\n );\n return resolveModuleSpecifierRecursively(loader, importedModule, [\n exportValue.imported,\n ...specifier.slice(1),\n ]);\n }\n // Namespace export\n // e.g. export * as colors from \"./colors\";\n else if (exportValue.type === \"star-export\") {\n const importedModule = await parseModule(\n loader,\n exportValue.from[0],\n path.dirname(module.filePath),\n );\n return resolveModuleSpecifierRecursively(\n loader,\n importedModule,\n specifier.slice(1),\n );\n }\n\n if (exportValue.type === \"styled-component\") {\n return {\n type: \"styled-component\",\n from: module.filePath,\n name: specifier[specifier.length - 1],\n };\n } else if (exportValue.type === \"constant\") {\n return { type: \"constant\", value: exportValue.value };\n } else if (exportValue.type === \"record\") {\n let current: any = exportValue.value;\n let depth = 0;\n /// Drill down the specifier e.g. colors.primary\n do {\n if (typeof current === \"string\" || typeof current === \"number\") {\n return {\n type: \"constant\" as const,\n value: current,\n };\n } else if (\n !current ||\n (typeof current !== \"object\" && !Array.isArray(current))\n ) {\n throw new Error(\n `Error unpacking Record/Array \"${exportName}\".\\nKey \"${\n specifier[depth]\n }\" was of type \"${typeof current}\" but only String and Number are supported`,\n );\n }\n depth++;\n // mixins in .yak files are wrapped inside an object with a __yak key\n if (depth === specifier.length && \"__yak\" in current) {\n return { type: \"mixin\", value: current[\"__yak\"] };\n } else if (depth === specifier.length && \"value\" in current) {\n return { type: \"constant\", value: current[\"value\"] };\n } else {\n current = current[specifier[depth]];\n }\n } while (current);\n if (specifier[depth] === undefined) {\n throw new Error(\n `Error unpacking Record/Array - could not extract \\`${specifier\n .slice(0, depth)\n .join(\".\")}\\` is not a string or number`,\n );\n }\n throw new Error(\n `Error unpacking Record/Array - could not extract \\`${\n specifier[depth]\n }\\` from \\`${specifier.slice(0, depth).join(\".\")}\\``,\n );\n } else if (exportValue.type === \"mixin\") {\n return { type: \"mixin\", value: exportValue.value };\n }\n throw new Error(\n `Error unpacking Record/Array - unexpected exportValue \"${\n exportValue.type\n }\" for specifier \"${specifier.join(\".\")}\"`,\n );\n } catch (error) {\n throw new Error(\n `Error resolving from module ${module.filePath}: ${\n (error as Error).message\n }`,\n );\n }\n}\n\ntype ParsedFile =\n | { type: \"regular\"; exports: Record<string, ParsedExport>; filePath: string }\n | { type: \"yak\"; exports: Record<string, ParsedExport>; filePath: string };\n\ntype ParsedExport =\n | { type: \"styled-component\" }\n | { type: \"mixin\"; value: string }\n | { type: \"constant\"; value: string | number }\n | { type: \"record\"; value: Record<any, ParsedExport> | {} }\n | { type: \"unsupported\" }\n | { type: \"re-export\"; from: string; imported: string }\n | { type: \"star-export\"; from: string[] };\n\ntype ResolvedExport =\n | { type: \"styled-component\"; from: string; name: string }\n | { type: \"mixin\"; value: string | number }\n | { type: \"constant\"; value: string | number };\n"],"mappings":"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","names":["path","module","babel","babelPlugin","import_path"]}
@@ -238,24 +238,48 @@ async function parseFile(
238
238
  // e.g. cross file mixins inside a cross file mixin
239
239
  // or a cross file selector inside a cross file mixin
240
240
  await Promise.all(
241
- Object.entries(mixins).map(async ([name, mixin]) => {
242
- mixins[name] = {
243
- type: "mixin",
244
- value: await resolveCrossFileConstant(
245
- loader,
246
- path.dirname(filePath),
247
- mixin.value,
248
- ),
249
- };
241
+ Object.entries(mixins).map(async ([name, { value, nameParts }]) => {
242
+ const resolvedValue = await resolveCrossFileConstant(
243
+ loader,
244
+ path.dirname(filePath),
245
+ value,
246
+ );
247
+ if (nameParts.length === 1) {
248
+ exports[name] = { type: "mixin", value: resolvedValue };
249
+ } else {
250
+ let exportEntry: undefined | ParsedExport = exports[nameParts[0]];
251
+ if (!exportEntry) {
252
+ exportEntry = { type: "record", value: {} };
253
+ exports[nameParts[0]] = exportEntry;
254
+ } else if (exportEntry.type !== "record") {
255
+ throw new Error(
256
+ `Error parsing file ${filePath}: ${nameParts[0]} is not a record`,
257
+ );
258
+ }
259
+ let current = exportEntry.value as Record<any, ParsedExport>;
260
+ for (let i = 1; i < nameParts.length - 1; i++) {
261
+ let next = current[nameParts[i]];
262
+ if (!next) {
263
+ next = { type: "record", value: {} };
264
+ current[nameParts[i]] = next;
265
+ } else if (next.type !== "record") {
266
+ throw new Error(
267
+ `Error parsing file ${filePath}: ${nameParts[i]} is not a record`,
268
+ );
269
+ }
270
+ current = next.value;
271
+ }
272
+ current[nameParts[nameParts.length - 1]] = {
273
+ type: "mixin",
274
+ value: resolvedValue,
275
+ };
276
+ }
250
277
  }),
251
278
  );
252
279
 
253
280
  return {
254
281
  type: "regular",
255
- exports: {
256
- ...exports,
257
- ...mixins,
258
- },
282
+ exports,
259
283
  filePath,
260
284
  };
261
285
  } catch (error) {
@@ -350,19 +374,27 @@ async function parseExports(
350
374
 
351
375
  function parseMixins(
352
376
  sourceContents: string,
353
- ): Record<string, { type: "mixin"; value: string }> {
377
+ ): Record<string, { type: "mixin"; value: string; nameParts: string[] }> {
354
378
  // Mixins are always in the following format:
355
- // /*YAK EXPORTED MIXIN:name
379
+ // /*YAK EXPORTED MIXIN:fancy:aspectRatio:16:9
356
380
  // css
357
381
  // */
358
382
  const mixinParts = sourceContents.split("/*YAK EXPORTED MIXIN:");
359
- let mixins: Record<string, { type: "mixin"; value: string }> = {};
383
+ let mixins: Record<
384
+ string,
385
+ { type: "mixin"; value: string; nameParts: string[] }
386
+ > = {};
387
+
360
388
  for (let i = 1; i < mixinParts.length; i++) {
361
389
  const [comment] = mixinParts[i].split("*/", 1);
362
390
  const position = comment.indexOf("\n");
363
391
  const name = comment.slice(0, position);
364
392
  const value = comment.slice(position + 1);
365
- mixins[name] = { type: "mixin", value };
393
+ mixins[name] = {
394
+ type: "mixin",
395
+ value,
396
+ nameParts: name.split(":").map((part) => decodeURIComponent(part)),
397
+ };
366
398
  }
367
399
  return mixins;
368
400
  }
@@ -407,8 +439,8 @@ function parseExportValueExpression(
407
439
 
408
440
  function parseObjectExpression(
409
441
  node: babel.types.ObjectExpression,
410
- ): Record<string, any> {
411
- let result: Record<string, any> = {};
442
+ ): Record<string, ParsedExport> {
443
+ let result: Record<string, ParsedExport> = {};
412
444
  for (const property of node.properties) {
413
445
  if (
414
446
  property.type === "ObjectProperty" &&
@@ -587,7 +619,7 @@ type ParsedExport =
587
619
  | { type: "styled-component" }
588
620
  | { type: "mixin"; value: string }
589
621
  | { type: "constant"; value: string | number }
590
- | { type: "record"; value: {} }
622
+ | { type: "record"; value: Record<any, ParsedExport> | {} }
591
623
  | { type: "unsupported" }
592
624
  | { type: "re-export"; from: string; imported: string }
593
625
  | { type: "star-export"; from: string[] };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-yak",
3
- "version": "1.1.4",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "types": "./dist/",
6
6
  "license": "MIT",
@@ -78,7 +78,7 @@
78
78
  "dependencies": {
79
79
  "@babel/core": "7.23.2",
80
80
  "@babel/plugin-syntax-typescript": "7.22.5",
81
- "yak-swc": "0.4.3"
81
+ "yak-swc": "0.4.4"
82
82
  },
83
83
  "devDependencies": {
84
84
  "@types/babel__core": "^7.1.14",