juisy 2.0.0-beta.9 → 2.1.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.
Files changed (30) hide show
  1. package/LICENSE +661 -0
  2. package/bin/cli/cmds/index.js +1 -3
  3. package/bin/cli/cmds/public/print-globals.js +1 -1
  4. package/dist/cli/CLIFactory.d.ts +2 -0
  5. package/dist/cli/Command.d.ts +46 -6
  6. package/dist/cli/GlobalSettings.schema.json +1 -1
  7. package/dist/cli/InterfaceUtils.d.ts +17 -13
  8. package/dist/cli/OutputUtils.d.ts +1 -12
  9. package/dist/cli/index.d.ts +1 -1
  10. package/dist/cli/index.js +504 -456
  11. package/dist/cli/plugins/register-bump-version-command/cmds/index.d.ts +14 -2
  12. package/dist/cli/plugins/register-lint-commands/augment.d.ts +2 -3
  13. package/dist/cli/plugins/register-lint-commands/settings.d.ts +1 -1
  14. package/dist/cli/plugins/register-release-command/augment.d.ts +2 -2
  15. package/dist/cli/types.d.ts +6 -2
  16. package/dist/cli/utils.d.ts +1 -10
  17. package/dist/eject.d.ts +2 -0
  18. package/dist/index.js +68 -13
  19. package/dist/project-globals.d.ts +7 -26
  20. package/dist/templater/index.js +2 -2
  21. package/dist/utils/misc.d.ts +43 -1
  22. package/dist/vite/plugins/inject-css-variables/index.d.ts +23 -0
  23. package/dist/vite/plugins/inject-css-variables/index.js +60 -0
  24. package/dist/vite/plugins/inject-project-globals/index.d.ts +19 -0
  25. package/dist/vite/plugins/inject-project-globals/index.js +58 -0
  26. package/package.json +198 -190
  27. package/bin/cli/cmds/public/squeeze.js +0 -269
  28. package/dist/cli/plugins/command-handler-injections/augment.d.ts +0 -29
  29. package/dist/cli/plugins/command-handler-injections/command-visitors/command-handler-injections.d.ts +0 -10
  30. package/dist/cli/plugins/command-handler-injections/index.d.ts +0 -3
@@ -1,3 +1,15 @@
1
1
  import { Command } from '../../../Command';
2
- declare const _default: Command;
3
- export default _default;
2
+ import { CLIEngine, CommandHandlerArgs } from '../../../types';
3
+ export default class BumpVersionCommand extends Command {
4
+ command: string;
5
+ describe: string;
6
+ meta: {
7
+ private: boolean;
8
+ };
9
+ builder(cli: CLIEngine): CLIEngine;
10
+ handler(argv: CommandHandlerArgs<{
11
+ preid: string;
12
+ file: string;
13
+ indent: number;
14
+ }>): Promise<void>;
15
+ }
@@ -1,5 +1,6 @@
1
1
  import { default as ESLint } from 'eslint';
2
2
  import { default as LintStaged } from 'lint-staged';
3
+ import { UserConfig as CommitLintConfig } from '@commitlint/types';
3
4
  import { SettingsLintMarkdown } from './types';
4
5
  declare module '../../types' {
5
6
  interface GlobalSettings {
@@ -14,10 +15,8 @@ declare module '../../types' {
14
15
  default?: UserProvidedConfigSetting<ESLint.Linter.LegacyConfig | ESLint.Linter.Config | ESLint.Linter.Config[]>;
15
16
  /**
16
17
  * Configuration for commitlint
17
- * See also: https://github.com/conventional-changelog/commitlint
18
- * Default: `{ extends: [ '@commitlint/config-conventional' ] }`
19
18
  */
20
- commit?: UserProvidedConfigSetting<{}>;
19
+ commit?: UserProvidedConfigSetting<CommitLintConfig>;
21
20
  /**
22
21
  * Configuration for markdownlint (markdownlint-cli2)
23
22
  */
@@ -5,7 +5,7 @@ import { SettingsLintMarkdown } from './types';
5
5
  */
6
6
  export default function resolveSettings(settings?: Required<GlobalSettings>['lint']): {
7
7
  default?: import('../..').UserProvidedConfigSetting<import("eslint").Linter.LegacyConfig | import("eslint").Linter.Config | import("eslint").Linter.Config[]>;
8
- commit?: import('../..').UserProvidedConfigSetting<{}>;
8
+ commit?: import('../..').UserProvidedConfigSetting<import('@commitlint/types').UserConfig>;
9
9
  markdown?: SettingsLintMarkdown;
10
10
  staged?: import('../..').UserProvidedConfigSetting<import('lint-staged').Config>;
11
11
  };
@@ -1,9 +1,9 @@
1
- import { default as ReleaseIt } from 'release-it';
1
+ import { Config as ReleaseItConfig } from 'release-it';
2
2
  declare module '../../types' {
3
3
  interface GlobalSettings {
4
4
  /**
5
5
  * Release configuration
6
6
  */
7
- release?: UserProvidedConfigSetting<ReleaseIt.Config>;
7
+ release?: UserProvidedConfigSetting<ReleaseItConfig>;
8
8
  }
9
9
  }
@@ -1,4 +1,4 @@
1
- import { Argv, CommandModule as YargsCommandModule, MiddlewareFunction } from 'yargs';
1
+ import { Argv, ArgumentsCamelCase, CommandModule as YargsCommandModule, MiddlewareFunction } from 'yargs';
2
2
  import { Command } from './Command';
3
3
  /**
4
4
  * An object whose all properties have the same type.
@@ -110,11 +110,15 @@ export interface CommandObject {
110
110
  /** string used as the description for the command in help text, use `false` for a hidden command */
111
111
  describe: YargsCommandModule['describe'];
112
112
  /** a function which will be passed the parsed argv. */
113
- handler: CommandHandler;
113
+ handler: YargsCommandModule['handler'];
114
114
  /** object declaring the options the command accepts, or a function accepting and returning a yargs instance */
115
115
  builder: (cli: CLIEngine) => CLIEngine | PromiseLike<CLIEngine>;
116
116
  middlewares?: MiddlewareFunction[];
117
117
  }
118
+ /**
119
+ * @group Types
120
+ */
121
+ export type CommandHandlerArgs<T = {}> = ArgumentsCamelCase<T>;
118
122
  /**
119
123
  * @group Types
120
124
  */
@@ -1,4 +1,4 @@
1
- import { CommandObject, CLIEngine, CommandHandler } from './types';
1
+ import { CommandObject, CLIEngine } from './types';
2
2
  /**
3
3
  * @ignore
4
4
  * @param target - The target builder
@@ -8,12 +8,3 @@ import { CommandObject, CLIEngine, CommandHandler } from './types';
8
8
  * that will be called before target. Target can be undefined
9
9
  */
10
10
  export declare function wrapCommandBuilder(target: CommandObject['builder'], builder: (cli: CLIEngine) => CLIEngine): (cli: CLIEngine) => CLIEngine | PromiseLike<CLIEngine>;
11
- /**
12
- * @ignore
13
- * @param target - The target handler
14
- * @param handler - The wrap
15
- * @description
16
- * Wrap command handler (target) with handler passed as second parameter
17
- * that will be called before target. Target can be undefined
18
- */
19
- export declare function wrapCommandhandler(target: CommandHandler, handler: CommandHandler): CommandHandler;
package/dist/eject.d.ts CHANGED
@@ -7,6 +7,7 @@ export type EjectOptions = {
7
7
  targetDir?: string;
8
8
  logLevel?: LogLevelDesc;
9
9
  ignoreFiles?: string[];
10
+ templateData?: Record<string, any> | ((identifier: string) => Record<string, any> | Promise<Record<string, any>>);
10
11
  processor?: (content: string, identifier: string) => string | Promise<string>;
11
12
  onError?: (identifier: string, fromPath: string, toPath: string, err: Error) => void | Promise<void>;
12
13
  onSuccess?: (identifier: string, fromPath: string, toPath: string) => void | Promise<void>;
@@ -17,6 +18,7 @@ export type EjectOptions = {
17
18
  * @param options - The options object
18
19
  * @param options.force - If true, the target files will be overwritten
19
20
  * @param options.targetDir - The target directory absolute path
21
+ * @param options.templateData - The template data object
20
22
  * @param options.processor - The template file content processor function.
21
23
  * Takes content as unique argument and must return string or a Promise that resolves a string
22
24
  * @param options.onError - The callback if an error occurs
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  /*!
2
- * juisy v2.0.0-beta.9
2
+ * juisy v2.1.0
3
3
  * Copyright © 2022-Present Hervé Perchec
4
4
  */
5
5
 
6
- import path, { dirname } from 'node:path';
6
+ import path$1, { dirname } from 'node:path';
7
7
  import { readdir, readFileSync } from 'node:fs';
8
8
  import { glob } from 'glob';
9
9
  import yaml from 'yaml';
@@ -24,7 +24,7 @@ function getFileUrls(pattern, options) {
24
24
  async function* getFiles(dir) {
25
25
  const dirents = await readdir(dir, { withFileTypes: true });
26
26
  for (const dirent of dirents) {
27
- const res = path.resolve(dir, dirent.name);
27
+ const res = path$1.resolve(dir, dirent.name);
28
28
  if (dirent.isDirectory()) {
29
29
  yield* getFiles(res);
30
30
  } else {
@@ -32,11 +32,61 @@ async function* getFiles(dir) {
32
32
  }
33
33
  }
34
34
  }
35
+ const path = {
36
+ /**
37
+ * Convert a path to win32 format (with `\\` separator)
38
+ * @param val - The path to convert
39
+ * @example
40
+ * utils.path.toWin32('a/posix/path') // => 'a\posix\path'
41
+ * utils.path.toWin32('C:\\a\\win32\\absolute\\path') // => 'C:\a\win32\absolute\path'
42
+ * utils.path.toWin32('a/mixed\\path') // => 'a\mixed\path'
43
+ */
44
+ toWin32(val) {
45
+ return val.split(path$1.posix.sep).join(path$1.win32.sep);
46
+ },
47
+ /**
48
+ * Convert a path to posix format (with `/` separator)
49
+ * @param val - The path to convert
50
+ * @example
51
+ * utils.path.toPosix('a/posix/path') // => 'a/posix/path'
52
+ * utils.path.toPosix('C:\\a\\win32\\absolute\\path') // => 'C:/a/win32/absolute/path'
53
+ * utils.path.toPosix('a/mixed\\path') // => 'a/mixed/path'
54
+ */
55
+ toPosix(val) {
56
+ return val.split(path$1.win32.sep).join(path$1.posix.sep);
57
+ },
58
+ /**
59
+ * Automatically convert a path to OS specific format
60
+ * @param val - The path to convert
61
+ */
62
+ toOsFormat(val) {
63
+ const platform = process.platform;
64
+ return platform === "win32" ? path.toWin32(val) : path.toPosix(val);
65
+ },
66
+ /**
67
+ * Util to resolve relative file path to root directory
68
+ * @param from - The "from" absolute file path
69
+ * @param to - The "to" absolute file path
70
+ * @param separator - (Optional) The separator type: can be `"posix"` or `"win32"`
71
+ * @returns The resolved relative path to root directory
72
+ * @example
73
+ * const base = 'C:\\Users\\JohnDoe\\Documents\\Projects\\MyProject'
74
+ *
75
+ * utils.path.resolveRel(base, 'C:\\Users\\JohnDoe\\Documents\\Projects\\MyProject\\src\\index.ts') // 'src\\index.ts'
76
+ * utils.path.resolveRel('C:\\Users\\JohnDoe\\Documents\\Projects\\MyProject\\src\\index.ts', base) // '..\\..'
77
+ * utils.path.resolveRel(base, 'C:\\Users\\JohnDoe\\Documents\\Projects\\MyProject\\src\\index.ts', 'posix') // 'src/index.ts'
78
+ */
79
+ resolveRel(from, to, separator) {
80
+ const relativePath = path$1.relative(from, to);
81
+ return separator ? separator === "posix" ? path.toPosix(relativePath) : path.toWin32(relativePath) : path.toOsFormat(relativePath);
82
+ }
83
+ };
35
84
 
36
85
  const misc = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
37
86
  __proto__: null,
38
87
  getFileUrls,
39
- getFiles
88
+ getFiles,
89
+ path
40
90
  }, Symbol.toStringTag, { value: 'Module' }));
41
91
 
42
92
  const xml = jstoxml.toXML;
@@ -121,8 +171,9 @@ async function isFile(filePath) {
121
171
  }
122
172
  }
123
173
  async function ejectFile(from, to, identifier = null, options) {
124
- identifier = identifier || path.basename(from);
174
+ identifier = identifier || path$1.basename(from);
125
175
  const force = options?.force || false;
176
+ const templateData = options?.templateData;
126
177
  const processor = options?.processor || (async (str, _identifier) => str);
127
178
  const onError = options?.onError || (async (_identifier, fromPath, toPath, err) => {
128
179
  throw err;
@@ -134,7 +185,7 @@ async function ejectFile(from, to, identifier = null, options) {
134
185
  const write = await fs.exists(to) ? force : true;
135
186
  if (write) {
136
187
  const template = await fs.readFile(from, { encoding: "utf8" });
137
- const content = await templater.render(template);
188
+ const content = await templater.render(template, typeof templateData === "function" ? await templateData(identifier) : templateData);
138
189
  const processedContent = await processor(content, identifier);
139
190
  await fs.ensureFile(to);
140
191
  await fs.writeFile(to, processedContent);
@@ -156,10 +207,12 @@ async function eject(templateDir, identifier, options) {
156
207
  throw new Error("eject: identifier is required");
157
208
  } else {
158
209
  try {
159
- const fullPath = path.resolve(templateDir, identifier);
210
+ const fullPath = path$1.resolve(templateDir, identifier);
160
211
  if (await isFile(fullPath)) {
161
212
  if (!ignoreFiles.includes(identifier)) {
162
- await ejectFile(fullPath, path.resolve(targetDir, identifier), identifier, {
213
+ await ejectFile(fullPath, path$1.resolve(targetDir, identifier), identifier, {
214
+ force: options?.force,
215
+ templateData: options?.templateData,
163
216
  processor: options?.processor,
164
217
  onSuccess: options?.onSuccess,
165
218
  onError: options?.onError
@@ -168,9 +221,11 @@ async function eject(templateDir, identifier, options) {
168
221
  } else {
169
222
  const globPattern = await isDirectory(fullPath) ? identifier + "/**/*" : identifier;
170
223
  for (const fileRelativePath of getFileUrls(globPattern, { cwd: templateDir, nodir: true, posix: true, dot: true })) {
171
- const fullTemplateFilePath = path.resolve(templateDir, fileRelativePath);
224
+ const fullTemplateFilePath = path$1.resolve(templateDir, fileRelativePath);
172
225
  if (!ignoreFiles.includes(fileRelativePath)) {
173
- await ejectFile(fullTemplateFilePath, path.resolve(targetDir, fileRelativePath), fileRelativePath, {
226
+ await ejectFile(fullTemplateFilePath, path$1.resolve(targetDir, fileRelativePath), fileRelativePath, {
227
+ force: options?.force,
228
+ templateData: options?.templateData,
174
229
  processor: options?.processor,
175
230
  onSuccess: options?.onSuccess,
176
231
  onError: options?.onError
@@ -186,7 +241,7 @@ async function eject(templateDir, identifier, options) {
186
241
  }
187
242
 
188
243
  function getPackageInfo() {
189
- const pkgPath = path.resolve(packageDirectorySync(), "./package.json");
244
+ const pkgPath = path$1.resolve(packageDirectorySync(), "./package.json");
190
245
  return JSON.parse(readFileSync(pkgPath, "utf8"));
191
246
  }
192
247
 
@@ -241,8 +296,8 @@ function defineGlobals(config, builder) {
241
296
  };
242
297
  return deepmerge(GLOBALS, JSON.parse(JSON.stringify(builder(ctx))));
243
298
  }
244
- async function getProjectGlobals(filePath = "./globals.config.js") {
245
- return (await import(pathToFileURL(path.resolve(filePath)))).default;
299
+ async function getProjectGlobals(filePath = "./project.globals.js") {
300
+ return (await import(pathToFileURL(path$1.resolve(filePath)))).default;
246
301
  }
247
302
 
248
303
  export { DataExporter, defineGlobals, eject, getPackageInfo, getProjectGlobals, misc as utils };
@@ -3,7 +3,7 @@ import { IPackageJson as PackageJson, IAuthor as PackageJsonAuthor, IRepository
3
3
  /**
4
4
  * @group Types
5
5
  */
6
- export type ProjectGlobals = Record<string, string | Record<string, unknown> | undefined> & {
6
+ export type DefaultProjectGlobals = {
7
7
  ENV: NodeJS.ProcessEnv;
8
8
  PACKAGE: {
9
9
  NAME: PackageJson['name'];
@@ -29,44 +29,25 @@ export type DotenvOptions = Omit<DotenvConfigOptions, 'processEnv'>;
29
29
  /**
30
30
  * @group Types
31
31
  */
32
- export type DefineGlobalsBuilder = (ctx: {
32
+ export type DefineGlobalsBuilder<T extends Record<string, any>> = (ctx: {
33
33
  env: NodeJS.ProcessEnv;
34
34
  pkg: PackageJson;
35
- }) => ProjectGlobals;
35
+ }) => T;
36
36
  /**
37
37
  * Define project globals
38
38
  * @param config - The config object
39
39
  * @param builder - The builder function
40
40
  * @returns The computed globals object
41
41
  */
42
- export declare function defineGlobals(config: {
42
+ export declare function defineGlobals<CustomGlobals extends Record<string, any>>(config: {
43
43
  env?: {
44
44
  map?: string[];
45
45
  dotenvOptions?: DotenvOptions;
46
46
  };
47
- }, builder: DefineGlobalsBuilder): {
48
- [x: string]: /*elided*/ any;
49
- ENV: NodeJS.ProcessEnv;
50
- PACKAGE: {
51
- NAME: PackageJson["name"];
52
- URL: PackageJson["url"];
53
- };
54
- VERSION: string;
55
- AUTHOR: {
56
- EMAIL: PackageJsonAuthor["email"];
57
- NAME: PackageJsonAuthor["name"];
58
- URL: PackageJsonAuthor["url"];
59
- };
60
- REPOSITORY: {
61
- TYPE: PackageJsonRepository["type"];
62
- URL: PackageJsonRepository["url"];
63
- };
64
- ISSUES_URL: string;
65
- HOMEPAGE: string;
66
- };
47
+ }, builder: DefineGlobalsBuilder<CustomGlobals>): DefaultProjectGlobals & CustomGlobals;
67
48
  /**
68
49
  * Get project globals
69
- * @param filePath - The filePath. Default is `'./globals.config.js'`
50
+ * @param filePath - The filePath. Default is `'./project.globals.js'`
70
51
  * @returns The resolved project globals object
71
52
  */
72
- export declare function getProjectGlobals(filePath?: string): Promise<ProjectGlobals>;
53
+ export declare function getProjectGlobals(filePath?: string): Promise<DefaultProjectGlobals & Record<string, string | Record<string, unknown> | undefined>>;
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * juisy v2.0.0-beta.9
2
+ * juisy v2.1.0
3
3
  * Copyright © 2022-Present Hervé Perchec
4
4
  */
5
5
 
@@ -184,7 +184,7 @@ class ReadmeTemplater {
184
184
  }, data), options.data);
185
185
  let template = await fs.readFile(processedConfig.templatePath, { encoding: "utf8" });
186
186
  if (processedConfig.appendAutoGenMessage) {
187
- template += "\n----\n\n*<%= $config.fileName %> - this file was auto generated with [juisy](https://www.npmjs.com/package/juisy) README templater. Don't edit it.*\n";
187
+ template += "\n----\n<!-- markdownlint-disable-next-line line-length -->\n*<%= $config.fileName %> - this file was auto generated with [juisy](https://www.npmjs.com/package/juisy) README templater. Don't edit it.*\n";
188
188
  }
189
189
  return await this.templater.render(template, ejsData, processedConfig.ejsOptions);
190
190
  }
@@ -1,7 +1,7 @@
1
1
  import { GlobOptions } from 'glob';
2
2
  /**
3
3
  * @param pattern - Same as node-glob pattern argument
4
- * @param options - Same as gloab options argument
4
+ * @param options - Same as glob options argument
5
5
  * @returns {string[]} Returns an array of file path
6
6
  * @description
7
7
  * Get file urls that match glob (see: https://github.com/isaacs/node-glob)
@@ -19,3 +19,45 @@ export declare function getFileUrls(pattern: string, options?: GlobOptions): str
19
19
  * utils.getFiles(path) // => [ 'path/to/file1', 'path/to/file2', ... ]
20
20
  */
21
21
  export declare function getFiles(dir: string): AsyncGenerator<string[]>;
22
+ /**
23
+ * Utils related to path
24
+ */
25
+ export declare const path: {
26
+ /**
27
+ * Convert a path to win32 format (with `\\` separator)
28
+ * @param val - The path to convert
29
+ * @example
30
+ * utils.path.toWin32('a/posix/path') // => 'a\posix\path'
31
+ * utils.path.toWin32('C:\\a\\win32\\absolute\\path') // => 'C:\a\win32\absolute\path'
32
+ * utils.path.toWin32('a/mixed\\path') // => 'a\mixed\path'
33
+ */
34
+ toWin32(val: string): string;
35
+ /**
36
+ * Convert a path to posix format (with `/` separator)
37
+ * @param val - The path to convert
38
+ * @example
39
+ * utils.path.toPosix('a/posix/path') // => 'a/posix/path'
40
+ * utils.path.toPosix('C:\\a\\win32\\absolute\\path') // => 'C:/a/win32/absolute/path'
41
+ * utils.path.toPosix('a/mixed\\path') // => 'a/mixed/path'
42
+ */
43
+ toPosix(val: string): string;
44
+ /**
45
+ * Automatically convert a path to OS specific format
46
+ * @param val - The path to convert
47
+ */
48
+ toOsFormat(val: string): string;
49
+ /**
50
+ * Util to resolve relative file path to root directory
51
+ * @param from - The "from" absolute file path
52
+ * @param to - The "to" absolute file path
53
+ * @param separator - (Optional) The separator type: can be `"posix"` or `"win32"`
54
+ * @returns The resolved relative path to root directory
55
+ * @example
56
+ * const base = 'C:\\Users\\JohnDoe\\Documents\\Projects\\MyProject'
57
+ *
58
+ * utils.path.resolveRel(base, 'C:\\Users\\JohnDoe\\Documents\\Projects\\MyProject\\src\\index.ts') // 'src\\index.ts'
59
+ * utils.path.resolveRel('C:\\Users\\JohnDoe\\Documents\\Projects\\MyProject\\src\\index.ts', base) // '..\\..'
60
+ * utils.path.resolveRel(base, 'C:\\Users\\JohnDoe\\Documents\\Projects\\MyProject\\src\\index.ts', 'posix') // 'src/index.ts'
61
+ */
62
+ resolveRel(from: string, to: string, separator?: "posix" | "win32"): string;
63
+ };
@@ -0,0 +1,23 @@
1
+ import { Plugin } from 'vite';
2
+ export type Options = {
3
+ /**
4
+ * The virtual module ID
5
+ */
6
+ moduleId: string;
7
+ /**
8
+ * The CSS selector.
9
+ * @default ':root'
10
+ */
11
+ selector?: string;
12
+ /**
13
+ * The CSS variables object
14
+ */
15
+ variables: Record<string, string>;
16
+ };
17
+ /**
18
+ * Inject CSS variables via a virtual module
19
+ * @param opts - The plugin options or an array of options
20
+ * @returns {Plugin} The vite plugin function
21
+ */
22
+ export declare function injectCssVariables(optsArg?: Options | Array<Options>): Plugin;
23
+ export default injectCssVariables;
@@ -0,0 +1,60 @@
1
+ /*!
2
+ * juisy v2.1.0
3
+ * Copyright © 2022-Present Hervé Perchec
4
+ */
5
+
6
+ function injectCssVariables(optsArg = []) {
7
+ const optionsArray = optsArg instanceof Array ? optsArg : [optsArg];
8
+ const virtualModules = /* @__PURE__ */ new Map();
9
+ for (let i = 0; i < optionsArray.length; i++) {
10
+ const options = optionsArray[i];
11
+ if (!options.moduleId || options.moduleId.trim().length === 0) {
12
+ throw new Error(`Please provide a non-empty module ID in plugin options at index ${i}`);
13
+ }
14
+ if (virtualModules.has(options.moduleId)) {
15
+ throw new Error(`The module ID "${options.moduleId}" is already used. Please provide another ID`);
16
+ }
17
+ virtualModules.set(options.moduleId, options);
18
+ }
19
+ return {
20
+ name: "vite-plugin-inject-css-variables",
21
+ enforce: "pre",
22
+ resolveId(id) {
23
+ const options = virtualModules.get(id);
24
+ if (!options) {
25
+ return;
26
+ } else {
27
+ return "\0" + options.moduleId;
28
+ }
29
+ },
30
+ async load(id) {
31
+ const options = virtualModules.get(id.slice(1));
32
+ if (!id.startsWith("\0") || !options) {
33
+ return;
34
+ }
35
+ const { selector = ":root", variables } = options;
36
+ try {
37
+ if (Object.keys(variables).length === 0) {
38
+ return "";
39
+ }
40
+ for (const key in variables) {
41
+ if (typeof variables[key] === "string") {
42
+ continue;
43
+ }
44
+ }
45
+ } catch (e) {
46
+ this.error(`The variables object for module "${options.moduleId}" is malformed`);
47
+ }
48
+ let css = `${selector} {
49
+ `;
50
+ for (const key in variables) {
51
+ css += ` --${key}: ${variables[key]};
52
+ `;
53
+ }
54
+ css += "}\n";
55
+ return css;
56
+ }
57
+ };
58
+ }
59
+
60
+ export { injectCssVariables as default, injectCssVariables };
@@ -0,0 +1,19 @@
1
+ import { Plugin } from 'vite';
2
+ export type Options = {
3
+ /**
4
+ * The virtual module ID
5
+ * @default 'virtual:project.globals.js'
6
+ */
7
+ moduleId?: string;
8
+ /**
9
+ * The project globals path (relative from root folder)
10
+ */
11
+ filePath?: string;
12
+ };
13
+ /**
14
+ * Inject project globals via a virtual module
15
+ * @param opts - The plugin options or an array of options
16
+ * @returns {Plugin} The vite plugin function
17
+ */
18
+ export declare function injectProjectGlobals(options?: Options): Plugin;
19
+ export default injectProjectGlobals;
@@ -0,0 +1,58 @@
1
+ /*!
2
+ * juisy v2.1.0
3
+ * Copyright © 2022-Present Hervé Perchec
4
+ */
5
+
6
+ import { getProjectGlobals } from 'juisy';
7
+ import { OutputUtils } from 'juisy/cli';
8
+
9
+ function injectProjectGlobals(options = {}) {
10
+ const { $style } = OutputUtils;
11
+ let config;
12
+ let moduleId = "virtual:project.globals.js";
13
+ if (options.moduleId) {
14
+ if (options.moduleId.trim().length === 0) {
15
+ throw new Error("Please provide a non-empty module ID for juisy/vite-plugin-inject-project-globals");
16
+ }
17
+ moduleId = options.moduleId;
18
+ }
19
+ return {
20
+ name: "vite-plugin-inject-project-globals",
21
+ enforce: "pre",
22
+ configResolved(resolvedConfig) {
23
+ config = resolvedConfig;
24
+ },
25
+ resolveId(id) {
26
+ if (id !== moduleId) {
27
+ return;
28
+ } else {
29
+ return "\0" + moduleId;
30
+ }
31
+ },
32
+ /**
33
+ * Vite plugin `load` hook
34
+ * @param id - The requested module ID
35
+ * @returns The module content as a string
36
+ * @description
37
+ * Load the virtual module and return its content.
38
+ * If the module ID is not the one defined by the plugin, simply return null.
39
+ * Otherwise, call `getProjectGlobals` and build a js string.
40
+ */
41
+ async load(id) {
42
+ if (!id.startsWith("\0") || id.slice(1) !== moduleId) {
43
+ return;
44
+ }
45
+ const PROJECT_GLOBALS = {
46
+ ...await getProjectGlobals(options.filePath)
47
+ };
48
+ if (PROJECT_GLOBALS.ENV) {
49
+ config.logger.warn("\n[vite-plugin-inject-project-globals] " + $style.yellow("The following ENV variables are exposed:"));
50
+ config.logger.warn(JSON.stringify(PROJECT_GLOBALS.ENV));
51
+ config.logger.warn("\n");
52
+ }
53
+ return "const PROJECT_GLOBALS = " + JSON.stringify(PROJECT_GLOBALS) + "\nconst isBrowser = import.meta.env.SSR === false\nif (isBrowser) {\n if (PROJECT_GLOBALS.ENV) {\n console.warn('[vite-plugin-inject-project-globals] WARNING: some ENV variables are exposed! Be careful, do not expose sensitive data!')\n }\n}\nexport default PROJECT_GLOBALS\n";
54
+ }
55
+ };
56
+ }
57
+
58
+ export { injectProjectGlobals as default, injectProjectGlobals };