{"version":3,"sources":["../src/index.ts","../../minifiable-keywords/src/index.ts","../src/shared.ts"],"sourcesContent":["import {\n  collectKeywordsAndGenerateTypes,\n  createPrefixedLogger,\n  generateModuleCode,\n  RESOLVED_VIRTUAL_MODULE_ID,\n  resolveOptions,\n  splitQuery,\n  VIRTUAL_MODULE_ID,\n  type KeywordsPluginOptions,\n  type PrefixedLogger,\n} from 'minifiable-keywords';\nimport type { Plugin } from 'rollup';\nimport { PLUGIN_NAME } from './shared';\n\nexport type { KeywordsPluginOptions } from 'minifiable-keywords';\n\nexport const keywordsPlugin = (options?: KeywordsPluginOptions): Plugin => {\n  const pluginOptions = resolveOptions(options);\n  let collectedKeywords: Set<string>;\n  let logger: PrefixedLogger;\n  const root = process.cwd();\n  const isDev = pluginOptions.isDev ?? process.env.NODE_ENV === 'development';\n\n  return {\n    name: PLUGIN_NAME,\n    api: {\n      options: pluginOptions,\n    },\n\n    async buildStart() {\n      const pluginThis = this;\n      logger = createPrefixedLogger(\n        {\n          info: pluginThis.info,\n          warn: pluginThis.warn,\n          error: pluginThis.error,\n        },\n        PLUGIN_NAME,\n        false,\n      );\n      collectedKeywords = await collectKeywordsAndGenerateTypes(\n        root,\n        logger,\n        [],\n        pluginOptions,\n      );\n    },\n\n    resolveId(source, importer) {\n      if (!importer) {\n        return;\n      }\n      const [validSource] = splitQuery(source);\n      if (validSource === VIRTUAL_MODULE_ID) {\n        return RESOLVED_VIRTUAL_MODULE_ID;\n      }\n    },\n\n    load(id) {\n      const [validId] = splitQuery(id);\n      if (validId === RESOLVED_VIRTUAL_MODULE_ID) {\n        return generateModuleCode(collectedKeywords, isDev);\n      }\n    },\n  };\n};\n\nexport default keywordsPlugin;\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { parse } from '@babel/parser';\nimport _traverse, { type Node } from '@babel/traverse';\nimport { globby } from 'globby';\n\nexport const VIRTUAL_MODULE_ID = 'virtual:keywords';\nexport const RESOLVED_VIRTUAL_MODULE_ID = `\\0${VIRTUAL_MODULE_ID}`;\n\nexport interface KeywordsPluginOptions {\n  additionalModulesToScan?: string[];\n  isDev?: boolean;\n}\n\nexport type ResolvedKeywordsPluginOptions = Required<\n  Omit<KeywordsPluginOptions, 'isDev'>\n> & { isDev?: boolean };\n\nexport const resolveOptions = (\n  options?: KeywordsPluginOptions,\n): ResolvedKeywordsPluginOptions => {\n  return {\n    additionalModulesToScan: options?.additionalModulesToScan || [],\n    isDev: options?.isDev,\n  };\n};\n\nexport interface Logger {\n  info: (message: string) => void;\n  warn: (message: string) => void;\n  error: (message: string) => void;\n}\n\nexport interface PrefixedLogger extends Logger {\n  pluginName: string;\n}\n\nexport const createPrefixedLogger = (\n  logger: Logger,\n  pluginName: string,\n  usePrefix: boolean = true,\n): PrefixedLogger => {\n  const prefix = usePrefix ? `[${pluginName}] ` : '';\n  const prefixed = (message: string) => `${prefix}${message}`;\n  return {\n    pluginName,\n    info: (message: string) => logger.info(prefixed(message)),\n    warn: (message: string) => logger.warn(prefixed(message)),\n    error: (message: string) => logger.error(prefixed(message)),\n  };\n};\n\n// ref: https://github.com/babel/babel/discussions/13093\nconst traverse =\n  typeof _traverse === 'function'\n    ? _traverse\n    : ((_traverse as any).default as typeof _traverse);\n\nexport const extractKeywords = (\n  code: string,\n  additionalModulesToScan: string[] = [],\n): Set<string> => {\n  const keywords = new Set<string>();\n\n  // Fast-path: Skip parsing if no relevant imports are present in the code.\n  const containsTargetModule =\n    code.includes(VIRTUAL_MODULE_ID) ||\n    additionalModulesToScan.some((moduleName) => code.includes(moduleName));\n\n  if (!containsTargetModule) {\n    return keywords;\n  }\n\n  let ast: Node;\n  try {\n    ast = parse(code, {\n      sourceType: 'module',\n      plugins: ['typescript', 'jsx'],\n      errorRecovery: true,\n    });\n  } catch (e) {\n    return keywords;\n  }\n\n  const keywordNamespaces = new Set<string>();\n\n  traverse(ast, {\n    enter(nodePath) {\n      const node = nodePath.node;\n\n      if (node.type === 'ImportDeclaration') {\n        const isTargetModule =\n          node.source.value === VIRTUAL_MODULE_ID ||\n          additionalModulesToScan.includes(node.source.value);\n\n        if (isTargetModule) {\n          for (const specifier of node.specifiers) {\n            if (specifier.type === 'ImportNamespaceSpecifier') {\n              keywordNamespaces.add(specifier.local.name);\n            }\n\n            if (specifier.type === 'ImportDefaultSpecifier') {\n              keywords.add('default');\n            }\n\n            if (specifier.type === 'ImportSpecifier') {\n              if (specifier.imported.type === 'Identifier') {\n                keywords.add(specifier.imported.name);\n              }\n            }\n          }\n        }\n      }\n    },\n  });\n\n  if (keywordNamespaces.size === 0) {\n    return keywords;\n  }\n\n  traverse(ast, {\n    enter(nodePath) {\n      const node = nodePath.node;\n\n      if (\n        node.type === 'MemberExpression' &&\n        !node.computed && // Exclude computed properties like K['xyz']\n        node.object.type === 'Identifier' &&\n        keywordNamespaces.has(node.object.name) &&\n        node.property.type === 'Identifier'\n      ) {\n        keywords.add(node.property.name);\n      }\n\n      if (\n        node.type === 'TSQualifiedName' &&\n        node.left.type === 'Identifier' &&\n        keywordNamespaces.has(node.left.name) &&\n        node.right.type === 'Identifier'\n      ) {\n        keywords.add(node.right.name);\n      }\n    },\n  });\n\n  return keywords;\n};\n\nconst keywordConstPrefix = '_';\nconst createExportDeclaration = (keywords: Set<string>): string[] => {\n  const aliases = [...keywords].map(\n    (key) => `  ${keywordConstPrefix}${key} as ${key},`,\n  );\n  return [`export {`, ...aliases, `};`];\n};\n\nexport const generateTypesFile = async (\n  collectedKeywords: Set<string>,\n  root: string,\n  dirname: string = '.keywords',\n  filename: string = 'index.d.ts',\n): Promise<void> => {\n  const keywordDeclarations = [...collectedKeywords]\n    .map((key) => `declare const ${keywordConstPrefix}${key}: unique symbol;`)\n    .join('\\n');\n  const exportDeclaration =\n    createExportDeclaration(collectedKeywords).join('\\n');\n  const content = `${keywordDeclarations}\\n${exportDeclaration}\\n`;\n  const pluginRoot = path.join(root, dirname);\n  await mkdir(pluginRoot, { recursive: true });\n  await writeFile(path.join(pluginRoot, filename), `${content.trim()}\\n`);\n};\n\nexport const collectKeywordsFromFiles = async (\n  root: string,\n  logger: PrefixedLogger,\n  ignoredDirs: string[] = [],\n  options?: KeywordsPluginOptions,\n): Promise<Set<string>> => {\n  const resolvedOptions = resolveOptions(options);\n  const collectedKeywords = new Set<string>();\n\n  logger.info('Scanning project files for keywords...');\n\n  const files = await globby('**/*.{js,ts,jsx,tsx}', {\n    cwd: root,\n    absolute: true,\n    ignore: ['**/node_modules/**', ...ignoredDirs.map((dir) => `${dir}/**`)],\n    gitignore: true,\n  });\n\n  const concurrency = 100;\n  for (let i = 0; i < files.length; i += concurrency) {\n    const chunk = files.slice(i, i + concurrency);\n    await Promise.all(\n      chunk.map(async (file) => {\n        try {\n          const code = await readFile(file, 'utf-8');\n          const keywords = extractKeywords(\n            code,\n            resolvedOptions.additionalModulesToScan,\n          );\n          for (const key of keywords) {\n            collectedKeywords.add(key);\n          }\n        } catch (error: any) {\n          logger.warn(`Failed to process file ${file}: ${error.message}`);\n        }\n      }),\n    );\n  }\n\n  logger.info(\n    `Scan complete. Found ${collectedKeywords.size} unique keywords.`,\n  );\n\n  return collectedKeywords;\n};\n\nexport const collectKeywordsAndGenerateTypes = async (\n  root: string,\n  logger: PrefixedLogger,\n  ignoredDirs?: string[],\n  options?: KeywordsPluginOptions,\n): Promise<Set<string>> => {\n  const collectedKeywords = await collectKeywordsFromFiles(\n    root,\n    logger,\n    ignoredDirs,\n    options,\n  );\n  await generateTypesFile(collectedKeywords, root);\n  return collectedKeywords;\n};\n\nexport const generateModuleCode = (\n  collectedKeywords: Set<string>,\n  isDev: boolean,\n): string => {\n  const symbolConstructorName = '__SYMBOL__';\n  const symbolDeclaration = `const ${symbolConstructorName} = Symbol;`;\n  const keywordDeclarations = [...collectedKeywords]\n    .map(\n      (key) =>\n        `const ${keywordConstPrefix}${key} = /* @__PURE__ */ ${symbolConstructorName}(${isDev ? `'${key}'` : ''});`,\n    )\n    .join('\\n');\n  const exportDeclaration =\n    createExportDeclaration(collectedKeywords).join('\\n');\n  return `${symbolDeclaration}\\n${keywordDeclarations}\\n${exportDeclaration}\\n`;\n};\n\nexport const splitQuery = (id: string) => id.split('?');\n","export const PLUGIN_NAME = 'rollup-plugin-keywords';\n"],"mappings":"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","names":["_traverse","path"]}