rollup-plugin-keywords 1.1.0 → 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.
package/dist/cli.js CHANGED
@@ -1,3 +1,7 @@
1
+ // src/cli.ts
2
+ import path2 from "path";
3
+ import { parseArgs } from "util";
4
+
1
5
  // ../minifiable-keywords/dist/index.js
2
6
  import { mkdir, readFile, writeFile } from "fs/promises";
3
7
  import path from "path";
@@ -6,6 +10,11 @@ import _traverse from "@babel/traverse";
6
10
  import { globby } from "globby";
7
11
  var VIRTUAL_MODULE_ID = "virtual:keywords";
8
12
  var RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
13
+ var buildOptions = (options = {}) => {
14
+ return {
15
+ additionalModulesToScan: options.additionalModulesToScan || []
16
+ };
17
+ };
9
18
  var createPrefixedLogger = (logger, pluginName, usePrefix = true) => {
10
19
  const prefix = usePrefix ? `[${pluginName}] ` : "";
11
20
  const prefixed = (message) => `${prefix}${message}`;
@@ -17,8 +26,12 @@ var createPrefixedLogger = (logger, pluginName, usePrefix = true) => {
17
26
  };
18
27
  };
19
28
  var traverse = typeof _traverse === "function" ? _traverse : _traverse.default;
20
- var extractKeywords = (code) => {
29
+ var extractKeywords = (code, additionalModulesToScan = []) => {
21
30
  const keywords = /* @__PURE__ */ new Set();
31
+ const containsTargetModule = code.includes(VIRTUAL_MODULE_ID) || additionalModulesToScan.some((moduleName) => code.includes(moduleName));
32
+ if (!containsTargetModule) {
33
+ return keywords;
34
+ }
22
35
  let ast;
23
36
  try {
24
37
  ast = parse(code, {
@@ -33,17 +46,20 @@ var extractKeywords = (code) => {
33
46
  traverse(ast, {
34
47
  enter(nodePath) {
35
48
  const node = nodePath.node;
36
- if (node.type === "ImportDeclaration" && node.source.value === VIRTUAL_MODULE_ID) {
37
- for (const specifier of node.specifiers) {
38
- if (specifier.type === "ImportNamespaceSpecifier") {
39
- keywordNamespaces.add(specifier.local.name);
40
- }
41
- if (specifier.type === "ImportDefaultSpecifier") {
42
- keywords.add("default");
43
- }
44
- if (specifier.type === "ImportSpecifier") {
45
- if (specifier.imported.type === "Identifier") {
46
- keywords.add(specifier.imported.name);
49
+ if (node.type === "ImportDeclaration") {
50
+ const isTargetModule = node.source.value === VIRTUAL_MODULE_ID || additionalModulesToScan.includes(node.source.value);
51
+ if (isTargetModule) {
52
+ for (const specifier of node.specifiers) {
53
+ if (specifier.type === "ImportNamespaceSpecifier") {
54
+ keywordNamespaces.add(specifier.local.name);
55
+ }
56
+ if (specifier.type === "ImportDefaultSpecifier") {
57
+ keywords.add("default");
58
+ }
59
+ if (specifier.type === "ImportSpecifier") {
60
+ if (specifier.imported.type === "Identifier") {
61
+ keywords.add(specifier.imported.name);
62
+ }
47
63
  }
48
64
  }
49
65
  }
@@ -74,7 +90,7 @@ var createExportDeclaration = (keywords) => {
74
90
  );
75
91
  return [`export {`, ...aliases, `};`];
76
92
  };
77
- var generateTypesFile = async (collectedKeywords, root, dirname = ".keywords", filename = "mod.d.ts") => {
93
+ var generateTypesFile = async (collectedKeywords, root, dirname = ".keywords", filename = "index.d.ts") => {
78
94
  const keywordDeclarations = [...collectedKeywords].map((key) => `declare const ${keywordConstPrefix}${key}: unique symbol;`).join("\n");
79
95
  const exportDeclaration = createExportDeclaration(collectedKeywords).join("\n");
80
96
  const content = `${keywordDeclarations}
@@ -85,7 +101,7 @@ ${exportDeclaration}
85
101
  await writeFile(path.join(pluginRoot, filename), `${content.trim()}
86
102
  `);
87
103
  };
88
- var collectKeywordsFromFiles = async (root, logger, ignoredDirs = []) => {
104
+ var collectKeywordsFromFiles = async (root, logger, ignoredDirs = [], options = buildOptions()) => {
89
105
  const collectedKeywords = /* @__PURE__ */ new Set();
90
106
  logger.info("Scanning project files for keywords...");
91
107
  const files = await globby("**/*.{js,ts,jsx,tsx}", {
@@ -94,30 +110,45 @@ var collectKeywordsFromFiles = async (root, logger, ignoredDirs = []) => {
94
110
  ignore: ["**/node_modules/**", ...ignoredDirs.map((dir) => `${dir}/**`)],
95
111
  gitignore: true
96
112
  });
97
- await Promise.all(
98
- files.map(async (file) => {
99
- const code = await readFile(file, "utf-8");
100
- const keywords = extractKeywords(code);
101
- for (const key of keywords) {
102
- collectedKeywords.add(key);
103
- }
104
- })
105
- );
113
+ const concurrency = 100;
114
+ for (let i = 0; i < files.length; i += concurrency) {
115
+ const chunk = files.slice(i, i + concurrency);
116
+ await Promise.all(
117
+ chunk.map(async (file) => {
118
+ try {
119
+ const code = await readFile(file, "utf-8");
120
+ const keywords = extractKeywords(
121
+ code,
122
+ options.additionalModulesToScan
123
+ );
124
+ for (const key of keywords) {
125
+ collectedKeywords.add(key);
126
+ }
127
+ } catch (error) {
128
+ logger.warn(`Failed to process file ${file}: ${error.message}`);
129
+ }
130
+ })
131
+ );
132
+ }
106
133
  logger.info(
107
134
  `Scan complete. Found ${collectedKeywords.size} unique keywords.`
108
135
  );
109
136
  return collectedKeywords;
110
137
  };
111
- var collectKeywordsAndGenerateTypes = async (root, logger, ignoredDirs) => {
138
+ var collectKeywordsAndGenerateTypes = async (root, logger, ignoredDirs, options) => {
112
139
  const collectedKeywords = await collectKeywordsFromFiles(
113
140
  root,
114
141
  logger,
115
- ignoredDirs
142
+ ignoredDirs,
143
+ options
116
144
  );
117
145
  await generateTypesFile(collectedKeywords, root);
118
146
  return collectedKeywords;
119
147
  };
120
148
 
149
+ // src/cli.ts
150
+ import { loadConfigFile } from "rollup/loadConfigFile";
151
+
121
152
  // src/shared.ts
122
153
  var PLUGIN_NAME = "rollup-plugin-keywords";
123
154
 
@@ -125,7 +156,60 @@ var PLUGIN_NAME = "rollup-plugin-keywords";
125
156
  var main = async () => {
126
157
  const root = process.cwd();
127
158
  const logger = createPrefixedLogger(console, PLUGIN_NAME);
128
- await collectKeywordsAndGenerateTypes(root, logger);
159
+ const { values } = parseArgs({
160
+ options: {
161
+ config: {
162
+ type: "string",
163
+ short: "c"
164
+ },
165
+ configPlugin: {
166
+ type: "string"
167
+ }
168
+ },
169
+ strict: false
170
+ });
171
+ const configPath = path2.resolve(
172
+ root,
173
+ typeof values.config === "string" ? values.config : "rollup.config.js"
174
+ );
175
+ const commandOptions = {};
176
+ if (typeof values.configPlugin === "string") {
177
+ commandOptions.configPlugin = values.configPlugin;
178
+ }
179
+ let pluginOptions;
180
+ let options;
181
+ let warnings;
182
+ try {
183
+ const loaded = await loadConfigFile(configPath, commandOptions);
184
+ options = loaded.options;
185
+ warnings = loaded.warnings;
186
+ warnings.flush();
187
+ } catch (error) {
188
+ logger.error(`Error loading Rollup configuration: ${error.message}`);
189
+ process.exit(1);
190
+ }
191
+ for (const option of options) {
192
+ if (!option.plugins) continue;
193
+ const keywordsPlugin = option.plugins.find(
194
+ (plugin) => plugin && plugin.name === PLUGIN_NAME
195
+ );
196
+ if (keywordsPlugin) {
197
+ pluginOptions = keywordsPlugin.api?.options;
198
+ break;
199
+ }
200
+ }
201
+ if (!pluginOptions) {
202
+ logger.error("Keywords plugin not found in Rollup configuration.");
203
+ process.exit(1);
204
+ }
205
+ try {
206
+ await collectKeywordsAndGenerateTypes(root, logger, [], pluginOptions);
207
+ } catch (error) {
208
+ logger.error(
209
+ `Failed to collect keywords and generate types: ${error.message}`
210
+ );
211
+ process.exit(1);
212
+ }
129
213
  };
130
214
  await main();
131
215
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../minifiable-keywords/src/index.ts","../src/shared.ts","../src/cli.ts"],"sourcesContent":["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 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 = (code: string): Set<string> => {\n const keywords = new Set<string>();\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 (\n node.type === 'ImportDeclaration' &&\n node.source.value === VIRTUAL_MODULE_ID\n ) {\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 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 = 'mod.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): Promise<Set<string>> => {\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 await Promise.all(\n files.map(async (file) => {\n const code = await readFile(file, 'utf-8');\n const keywords = extractKeywords(code);\n for (const key of keywords) {\n collectedKeywords.add(key);\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): Promise<Set<string>> => {\n const collectedKeywords = await collectKeywordsFromFiles(\n root,\n logger,\n ignoredDirs,\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","import {\n collectKeywordsAndGenerateTypes,\n createPrefixedLogger,\n} from 'minifiable-keywords';\nimport { PLUGIN_NAME } from './shared';\n\nconst main = async () => {\n const root = process.cwd();\n const logger = createPrefixedLogger(console, PLUGIN_NAME);\n await collectKeywordsAndGenerateTypes(root, logger);\n};\n\nawait main();\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts","../../minifiable-keywords/src/index.ts","../src/shared.ts"],"sourcesContent":["import path from 'node:path';\nimport { parseArgs } from 'node:util';\nimport {\n collectKeywordsAndGenerateTypes,\n createPrefixedLogger,\n} from 'minifiable-keywords';\nimport { loadConfigFile } from 'rollup/loadConfigFile';\nimport { PLUGIN_NAME } from './shared';\n\nconst main = async () => {\n const root = process.cwd();\n const logger = createPrefixedLogger(console, PLUGIN_NAME);\n\n const { values } = parseArgs({\n options: {\n config: {\n type: 'string',\n short: 'c',\n },\n configPlugin: {\n type: 'string',\n },\n },\n strict: false,\n });\n\n const configPath = path.resolve(\n root,\n typeof values.config === 'string' ? values.config : 'rollup.config.js',\n );\n\n const commandOptions: Record<string, any> = {};\n if (typeof values.configPlugin === 'string') {\n commandOptions.configPlugin = values.configPlugin;\n }\n\n let pluginOptions;\n let options;\n let warnings;\n\n try {\n const loaded = await loadConfigFile(configPath, commandOptions);\n options = loaded.options;\n warnings = loaded.warnings;\n warnings.flush();\n } catch (error: any) {\n logger.error(`Error loading Rollup configuration: ${error.message}`);\n process.exit(1);\n }\n\n for (const option of options) {\n if (!option.plugins) continue;\n\n const keywordsPlugin = option.plugins.find(\n (plugin: any) => plugin && plugin.name === PLUGIN_NAME,\n );\n\n if (keywordsPlugin) {\n pluginOptions = (keywordsPlugin as any).api?.options;\n break;\n }\n }\n\n if (!pluginOptions) {\n logger.error('Keywords plugin not found in Rollup configuration.');\n process.exit(1);\n }\n\n try {\n await collectKeywordsAndGenerateTypes(root, logger, [], pluginOptions);\n } catch (error: any) {\n logger.error(\n `Failed to collect keywords and generate types: ${error.message}`,\n );\n process.exit(1);\n }\n};\n\nawait main();\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}\n\nexport const buildOptions = (\n options: Partial<KeywordsPluginOptions> = {},\n): KeywordsPluginOptions => {\n return {\n additionalModulesToScan: options.additionalModulesToScan || [],\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 = buildOptions(),\n): Promise<Set<string>> => {\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 options.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":["path","path"]}
package/dist/index.cjs CHANGED
@@ -43,6 +43,11 @@ var import_traverse = __toESM(require("@babel/traverse"), 1);
43
43
  var import_globby = require("globby");
44
44
  var VIRTUAL_MODULE_ID = "virtual:keywords";
45
45
  var RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
46
+ var buildOptions = (options = {}) => {
47
+ return {
48
+ additionalModulesToScan: options.additionalModulesToScan || []
49
+ };
50
+ };
46
51
  var createPrefixedLogger = (logger, pluginName, usePrefix = true) => {
47
52
  const prefix = usePrefix ? `[${pluginName}] ` : "";
48
53
  const prefixed = (message) => `${prefix}${message}`;
@@ -54,8 +59,12 @@ var createPrefixedLogger = (logger, pluginName, usePrefix = true) => {
54
59
  };
55
60
  };
56
61
  var traverse = typeof import_traverse.default === "function" ? import_traverse.default : import_traverse.default.default;
57
- var extractKeywords = (code) => {
62
+ var extractKeywords = (code, additionalModulesToScan = []) => {
58
63
  const keywords = /* @__PURE__ */ new Set();
64
+ const containsTargetModule = code.includes(VIRTUAL_MODULE_ID) || additionalModulesToScan.some((moduleName) => code.includes(moduleName));
65
+ if (!containsTargetModule) {
66
+ return keywords;
67
+ }
59
68
  let ast;
60
69
  try {
61
70
  ast = (0, import_parser.parse)(code, {
@@ -70,17 +79,20 @@ var extractKeywords = (code) => {
70
79
  traverse(ast, {
71
80
  enter(nodePath) {
72
81
  const node = nodePath.node;
73
- if (node.type === "ImportDeclaration" && node.source.value === VIRTUAL_MODULE_ID) {
74
- for (const specifier of node.specifiers) {
75
- if (specifier.type === "ImportNamespaceSpecifier") {
76
- keywordNamespaces.add(specifier.local.name);
77
- }
78
- if (specifier.type === "ImportDefaultSpecifier") {
79
- keywords.add("default");
80
- }
81
- if (specifier.type === "ImportSpecifier") {
82
- if (specifier.imported.type === "Identifier") {
83
- keywords.add(specifier.imported.name);
82
+ if (node.type === "ImportDeclaration") {
83
+ const isTargetModule = node.source.value === VIRTUAL_MODULE_ID || additionalModulesToScan.includes(node.source.value);
84
+ if (isTargetModule) {
85
+ for (const specifier of node.specifiers) {
86
+ if (specifier.type === "ImportNamespaceSpecifier") {
87
+ keywordNamespaces.add(specifier.local.name);
88
+ }
89
+ if (specifier.type === "ImportDefaultSpecifier") {
90
+ keywords.add("default");
91
+ }
92
+ if (specifier.type === "ImportSpecifier") {
93
+ if (specifier.imported.type === "Identifier") {
94
+ keywords.add(specifier.imported.name);
95
+ }
84
96
  }
85
97
  }
86
98
  }
@@ -111,7 +123,7 @@ var createExportDeclaration = (keywords) => {
111
123
  );
112
124
  return [`export {`, ...aliases, `};`];
113
125
  };
114
- var generateTypesFile = async (collectedKeywords, root, dirname = ".keywords", filename = "mod.d.ts") => {
126
+ var generateTypesFile = async (collectedKeywords, root, dirname = ".keywords", filename = "index.d.ts") => {
115
127
  const keywordDeclarations = [...collectedKeywords].map((key) => `declare const ${keywordConstPrefix}${key}: unique symbol;`).join("\n");
116
128
  const exportDeclaration = createExportDeclaration(collectedKeywords).join("\n");
117
129
  const content = `${keywordDeclarations}
@@ -122,7 +134,7 @@ ${exportDeclaration}
122
134
  await (0, import_promises.writeFile)(import_path.default.join(pluginRoot, filename), `${content.trim()}
123
135
  `);
124
136
  };
125
- var collectKeywordsFromFiles = async (root, logger, ignoredDirs = []) => {
137
+ var collectKeywordsFromFiles = async (root, logger, ignoredDirs = [], options = buildOptions()) => {
126
138
  const collectedKeywords = /* @__PURE__ */ new Set();
127
139
  logger.info("Scanning project files for keywords...");
128
140
  const files = await (0, import_globby.globby)("**/*.{js,ts,jsx,tsx}", {
@@ -131,25 +143,37 @@ var collectKeywordsFromFiles = async (root, logger, ignoredDirs = []) => {
131
143
  ignore: ["**/node_modules/**", ...ignoredDirs.map((dir) => `${dir}/**`)],
132
144
  gitignore: true
133
145
  });
134
- await Promise.all(
135
- files.map(async (file) => {
136
- const code = await (0, import_promises.readFile)(file, "utf-8");
137
- const keywords = extractKeywords(code);
138
- for (const key of keywords) {
139
- collectedKeywords.add(key);
140
- }
141
- })
142
- );
146
+ const concurrency = 100;
147
+ for (let i = 0; i < files.length; i += concurrency) {
148
+ const chunk = files.slice(i, i + concurrency);
149
+ await Promise.all(
150
+ chunk.map(async (file) => {
151
+ try {
152
+ const code = await (0, import_promises.readFile)(file, "utf-8");
153
+ const keywords = extractKeywords(
154
+ code,
155
+ options.additionalModulesToScan
156
+ );
157
+ for (const key of keywords) {
158
+ collectedKeywords.add(key);
159
+ }
160
+ } catch (error) {
161
+ logger.warn(`Failed to process file ${file}: ${error.message}`);
162
+ }
163
+ })
164
+ );
165
+ }
143
166
  logger.info(
144
167
  `Scan complete. Found ${collectedKeywords.size} unique keywords.`
145
168
  );
146
169
  return collectedKeywords;
147
170
  };
148
- var collectKeywordsAndGenerateTypes = async (root, logger, ignoredDirs) => {
171
+ var collectKeywordsAndGenerateTypes = async (root, logger, ignoredDirs, options) => {
149
172
  const collectedKeywords = await collectKeywordsFromFiles(
150
173
  root,
151
174
  logger,
152
- ignoredDirs
175
+ ignoredDirs,
176
+ options
153
177
  );
154
178
  await generateTypesFile(collectedKeywords, root);
155
179
  return collectedKeywords;
@@ -172,13 +196,17 @@ var splitQuery = (id) => id.split("?");
172
196
  var PLUGIN_NAME = "rollup-plugin-keywords";
173
197
 
174
198
  // src/index.ts
175
- var keywordsPlugin = () => {
199
+ var keywordsPlugin = (options) => {
200
+ const pluginOptions = buildOptions(options);
176
201
  let collectedKeywords;
177
202
  let logger;
178
203
  const root = process.cwd();
179
204
  const isDev = process.env.NODE_ENV === "development";
180
205
  return {
181
206
  name: PLUGIN_NAME,
207
+ api: {
208
+ options: pluginOptions
209
+ },
182
210
  async buildStart() {
183
211
  const pluginThis = this;
184
212
  logger = createPrefixedLogger(
@@ -190,7 +218,12 @@ var keywordsPlugin = () => {
190
218
  PLUGIN_NAME,
191
219
  false
192
220
  );
193
- collectedKeywords = await collectKeywordsAndGenerateTypes(root, logger);
221
+ collectedKeywords = await collectKeywordsAndGenerateTypes(
222
+ root,
223
+ logger,
224
+ [],
225
+ pluginOptions
226
+ );
194
227
  },
195
228
  resolveId(source, importer) {
196
229
  if (!importer) {
@@ -1 +1 @@
1
- {"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 splitQuery,\n VIRTUAL_MODULE_ID,\n type PrefixedLogger,\n} from 'minifiable-keywords';\nimport type { Plugin } from 'rollup';\nimport { PLUGIN_NAME } from './shared';\n\nexport const keywordsPlugin = (): Plugin => {\n let collectedKeywords: Set<string>;\n let logger: PrefixedLogger;\n const root = process.cwd();\n const isDev = process.env.NODE_ENV === 'development';\n\n return {\n name: PLUGIN_NAME,\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(root, logger);\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 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 = (code: string): Set<string> => {\n const keywords = new Set<string>();\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 (\n node.type === 'ImportDeclaration' &&\n node.source.value === VIRTUAL_MODULE_ID\n ) {\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 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 = 'mod.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): Promise<Set<string>> => {\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 await Promise.all(\n files.map(async (file) => {\n const code = await readFile(file, 'utf-8');\n const keywords = extractKeywords(code);\n for (const key of keywords) {\n collectedKeywords.add(key);\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): Promise<Set<string>> => {\n const collectedKeywords = await collectKeywordsFromFiles(\n root,\n logger,\n ignoredDirs,\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"]}
1
+ {"version":3,"sources":["../src/index.ts","../../minifiable-keywords/src/index.ts","../src/shared.ts"],"sourcesContent":["import {\n buildOptions,\n collectKeywordsAndGenerateTypes,\n createPrefixedLogger,\n generateModuleCode,\n RESOLVED_VIRTUAL_MODULE_ID,\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 const keywordsPlugin = (\n options?: Partial<KeywordsPluginOptions>,\n): Plugin => {\n const pluginOptions = buildOptions(options);\n let collectedKeywords: Set<string>;\n let logger: PrefixedLogger;\n const root = process.cwd();\n const 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}\n\nexport const buildOptions = (\n options: Partial<KeywordsPluginOptions> = {},\n): KeywordsPluginOptions => {\n return {\n additionalModulesToScan: options.additionalModulesToScan || [],\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 = buildOptions(),\n): Promise<Set<string>> => {\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 options.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"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,6 @@
1
+ import { KeywordsPluginOptions } from 'minifiable-keywords';
1
2
  import { Plugin } from 'rollup';
2
3
 
3
- declare const keywordsPlugin: () => Plugin;
4
+ declare const keywordsPlugin: (options?: Partial<KeywordsPluginOptions>) => Plugin;
4
5
 
5
6
  export { keywordsPlugin as default, keywordsPlugin };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
+ import { KeywordsPluginOptions } from 'minifiable-keywords';
1
2
  import { Plugin } from 'rollup';
2
3
 
3
- declare const keywordsPlugin: () => Plugin;
4
+ declare const keywordsPlugin: (options?: Partial<KeywordsPluginOptions>) => Plugin;
4
5
 
5
6
  export { keywordsPlugin as default, keywordsPlugin };
package/dist/index.js CHANGED
@@ -6,6 +6,11 @@ import _traverse from "@babel/traverse";
6
6
  import { globby } from "globby";
7
7
  var VIRTUAL_MODULE_ID = "virtual:keywords";
8
8
  var RESOLVED_VIRTUAL_MODULE_ID = `\0${VIRTUAL_MODULE_ID}`;
9
+ var buildOptions = (options = {}) => {
10
+ return {
11
+ additionalModulesToScan: options.additionalModulesToScan || []
12
+ };
13
+ };
9
14
  var createPrefixedLogger = (logger, pluginName, usePrefix = true) => {
10
15
  const prefix = usePrefix ? `[${pluginName}] ` : "";
11
16
  const prefixed = (message) => `${prefix}${message}`;
@@ -17,8 +22,12 @@ var createPrefixedLogger = (logger, pluginName, usePrefix = true) => {
17
22
  };
18
23
  };
19
24
  var traverse = typeof _traverse === "function" ? _traverse : _traverse.default;
20
- var extractKeywords = (code) => {
25
+ var extractKeywords = (code, additionalModulesToScan = []) => {
21
26
  const keywords = /* @__PURE__ */ new Set();
27
+ const containsTargetModule = code.includes(VIRTUAL_MODULE_ID) || additionalModulesToScan.some((moduleName) => code.includes(moduleName));
28
+ if (!containsTargetModule) {
29
+ return keywords;
30
+ }
22
31
  let ast;
23
32
  try {
24
33
  ast = parse(code, {
@@ -33,17 +42,20 @@ var extractKeywords = (code) => {
33
42
  traverse(ast, {
34
43
  enter(nodePath) {
35
44
  const node = nodePath.node;
36
- if (node.type === "ImportDeclaration" && node.source.value === VIRTUAL_MODULE_ID) {
37
- for (const specifier of node.specifiers) {
38
- if (specifier.type === "ImportNamespaceSpecifier") {
39
- keywordNamespaces.add(specifier.local.name);
40
- }
41
- if (specifier.type === "ImportDefaultSpecifier") {
42
- keywords.add("default");
43
- }
44
- if (specifier.type === "ImportSpecifier") {
45
- if (specifier.imported.type === "Identifier") {
46
- keywords.add(specifier.imported.name);
45
+ if (node.type === "ImportDeclaration") {
46
+ const isTargetModule = node.source.value === VIRTUAL_MODULE_ID || additionalModulesToScan.includes(node.source.value);
47
+ if (isTargetModule) {
48
+ for (const specifier of node.specifiers) {
49
+ if (specifier.type === "ImportNamespaceSpecifier") {
50
+ keywordNamespaces.add(specifier.local.name);
51
+ }
52
+ if (specifier.type === "ImportDefaultSpecifier") {
53
+ keywords.add("default");
54
+ }
55
+ if (specifier.type === "ImportSpecifier") {
56
+ if (specifier.imported.type === "Identifier") {
57
+ keywords.add(specifier.imported.name);
58
+ }
47
59
  }
48
60
  }
49
61
  }
@@ -74,7 +86,7 @@ var createExportDeclaration = (keywords) => {
74
86
  );
75
87
  return [`export {`, ...aliases, `};`];
76
88
  };
77
- var generateTypesFile = async (collectedKeywords, root, dirname = ".keywords", filename = "mod.d.ts") => {
89
+ var generateTypesFile = async (collectedKeywords, root, dirname = ".keywords", filename = "index.d.ts") => {
78
90
  const keywordDeclarations = [...collectedKeywords].map((key) => `declare const ${keywordConstPrefix}${key}: unique symbol;`).join("\n");
79
91
  const exportDeclaration = createExportDeclaration(collectedKeywords).join("\n");
80
92
  const content = `${keywordDeclarations}
@@ -85,7 +97,7 @@ ${exportDeclaration}
85
97
  await writeFile(path.join(pluginRoot, filename), `${content.trim()}
86
98
  `);
87
99
  };
88
- var collectKeywordsFromFiles = async (root, logger, ignoredDirs = []) => {
100
+ var collectKeywordsFromFiles = async (root, logger, ignoredDirs = [], options = buildOptions()) => {
89
101
  const collectedKeywords = /* @__PURE__ */ new Set();
90
102
  logger.info("Scanning project files for keywords...");
91
103
  const files = await globby("**/*.{js,ts,jsx,tsx}", {
@@ -94,25 +106,37 @@ var collectKeywordsFromFiles = async (root, logger, ignoredDirs = []) => {
94
106
  ignore: ["**/node_modules/**", ...ignoredDirs.map((dir) => `${dir}/**`)],
95
107
  gitignore: true
96
108
  });
97
- await Promise.all(
98
- files.map(async (file) => {
99
- const code = await readFile(file, "utf-8");
100
- const keywords = extractKeywords(code);
101
- for (const key of keywords) {
102
- collectedKeywords.add(key);
103
- }
104
- })
105
- );
109
+ const concurrency = 100;
110
+ for (let i = 0; i < files.length; i += concurrency) {
111
+ const chunk = files.slice(i, i + concurrency);
112
+ await Promise.all(
113
+ chunk.map(async (file) => {
114
+ try {
115
+ const code = await readFile(file, "utf-8");
116
+ const keywords = extractKeywords(
117
+ code,
118
+ options.additionalModulesToScan
119
+ );
120
+ for (const key of keywords) {
121
+ collectedKeywords.add(key);
122
+ }
123
+ } catch (error) {
124
+ logger.warn(`Failed to process file ${file}: ${error.message}`);
125
+ }
126
+ })
127
+ );
128
+ }
106
129
  logger.info(
107
130
  `Scan complete. Found ${collectedKeywords.size} unique keywords.`
108
131
  );
109
132
  return collectedKeywords;
110
133
  };
111
- var collectKeywordsAndGenerateTypes = async (root, logger, ignoredDirs) => {
134
+ var collectKeywordsAndGenerateTypes = async (root, logger, ignoredDirs, options) => {
112
135
  const collectedKeywords = await collectKeywordsFromFiles(
113
136
  root,
114
137
  logger,
115
- ignoredDirs
138
+ ignoredDirs,
139
+ options
116
140
  );
117
141
  await generateTypesFile(collectedKeywords, root);
118
142
  return collectedKeywords;
@@ -135,13 +159,17 @@ var splitQuery = (id) => id.split("?");
135
159
  var PLUGIN_NAME = "rollup-plugin-keywords";
136
160
 
137
161
  // src/index.ts
138
- var keywordsPlugin = () => {
162
+ var keywordsPlugin = (options) => {
163
+ const pluginOptions = buildOptions(options);
139
164
  let collectedKeywords;
140
165
  let logger;
141
166
  const root = process.cwd();
142
167
  const isDev = process.env.NODE_ENV === "development";
143
168
  return {
144
169
  name: PLUGIN_NAME,
170
+ api: {
171
+ options: pluginOptions
172
+ },
145
173
  async buildStart() {
146
174
  const pluginThis = this;
147
175
  logger = createPrefixedLogger(
@@ -153,7 +181,12 @@ var keywordsPlugin = () => {
153
181
  PLUGIN_NAME,
154
182
  false
155
183
  );
156
- collectedKeywords = await collectKeywordsAndGenerateTypes(root, logger);
184
+ collectedKeywords = await collectKeywordsAndGenerateTypes(
185
+ root,
186
+ logger,
187
+ [],
188
+ pluginOptions
189
+ );
157
190
  },
158
191
  resolveId(source, importer) {
159
192
  if (!importer) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../minifiable-keywords/src/index.ts","../src/shared.ts","../src/index.ts"],"sourcesContent":["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 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 = (code: string): Set<string> => {\n const keywords = new Set<string>();\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 (\n node.type === 'ImportDeclaration' &&\n node.source.value === VIRTUAL_MODULE_ID\n ) {\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 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 = 'mod.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): Promise<Set<string>> => {\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 await Promise.all(\n files.map(async (file) => {\n const code = await readFile(file, 'utf-8');\n const keywords = extractKeywords(code);\n for (const key of keywords) {\n collectedKeywords.add(key);\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): Promise<Set<string>> => {\n const collectedKeywords = await collectKeywordsFromFiles(\n root,\n logger,\n ignoredDirs,\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","import {\n collectKeywordsAndGenerateTypes,\n createPrefixedLogger,\n generateModuleCode,\n RESOLVED_VIRTUAL_MODULE_ID,\n splitQuery,\n VIRTUAL_MODULE_ID,\n type PrefixedLogger,\n} from 'minifiable-keywords';\nimport type { Plugin } from 'rollup';\nimport { PLUGIN_NAME } from './shared';\n\nexport const keywordsPlugin = (): Plugin => {\n let collectedKeywords: Set<string>;\n let logger: PrefixedLogger;\n const root = process.cwd();\n const isDev = process.env.NODE_ENV === 'development';\n\n return {\n name: PLUGIN_NAME,\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(root, logger);\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"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../minifiable-keywords/src/index.ts","../src/shared.ts","../src/index.ts"],"sourcesContent":["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}\n\nexport const buildOptions = (\n options: Partial<KeywordsPluginOptions> = {},\n): KeywordsPluginOptions => {\n return {\n additionalModulesToScan: options.additionalModulesToScan || [],\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 = buildOptions(),\n): Promise<Set<string>> => {\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 options.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","import {\n buildOptions,\n collectKeywordsAndGenerateTypes,\n createPrefixedLogger,\n generateModuleCode,\n RESOLVED_VIRTUAL_MODULE_ID,\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 const keywordsPlugin = (\n options?: Partial<KeywordsPluginOptions>,\n): Plugin => {\n const pluginOptions = buildOptions(options);\n let collectedKeywords: Set<string>;\n let logger: PrefixedLogger;\n const root = process.cwd();\n const 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"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rollup-plugin-keywords",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "A Rollup plugin that provides minifiable Symbols (keywords) to use in place of string literals for aggressive minification/obfuscation.",
5
5
  "keywords": [
6
6
  "rollup",
@@ -46,7 +46,7 @@
46
46
  "rimraf": "^6.0.1",
47
47
  "tsup": "^8.5.0",
48
48
  "vitest": "^4.0.0",
49
- "minifiable-keywords": "1.1.0"
49
+ "minifiable-keywords": "1.2.0"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "rollup": "^3.0.0 || ^4.0.0"