@grafana/create-plugin 6.1.1-canary.2232.18584719214.0 → 6.2.0-canary.2233.18586197736.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/README.md CHANGED
@@ -122,6 +122,45 @@ For more information see our [documentation](https://grafana.com/developers/plug
122
122
 
123
123
  ---
124
124
 
125
+ ## Add optional features to your existing plugin
126
+
127
+ You can add optional features to your plugin using the `add` command. This allows you to enhance your plugin with additional capabilities without starting from scratch.
128
+
129
+ ### Add internationalization (i18n) support
130
+
131
+ Add translation support to make your plugin available in multiple languages:
132
+
133
+ ```bash
134
+ # Run this command from the root of your plugin
135
+ cd ./my-plugin
136
+
137
+ npx @grafana/create-plugin@latest add i18n
138
+ ```
139
+
140
+ This will:
141
+
142
+ - Update your `plugin.json` with the selected languages
143
+ - Create locale folders and translation files
144
+ - Add the necessary dependencies to `package.json`
145
+ - Configure your docker-compose.yaml with the required feature toggle
146
+ - Add i18n imports to your module file
147
+ - Set up the i18n extraction script
148
+
149
+ The command will prompt you to select which locales you want to support. You can choose from common locales like:
150
+
151
+ - English (US) - `en-US`
152
+ - Spanish (Spain) - `es-ES`
153
+ - French (France) - `fr-FR`
154
+ - German (Germany) - `de-DE`
155
+ - Swedish (Sweden) - `sv-SE`
156
+ - And more...
157
+
158
+ You can also add custom locale codes during the interactive prompt.
159
+
160
+ For more information about plugin internationalization, see our [documentation](https://grafana.com/developers/plugin-tools/how-to-guides/plugin-internationalization).
161
+
162
+ ---
163
+
125
164
  ## Contributing
126
165
 
127
166
  We are always grateful for contributions! See [CONTRIBUTING.md](../../CONTRIBUTING.md) for more information.
@@ -0,0 +1,11 @@
1
+ var defaultAdditions = {
2
+ additions: {
3
+ i18n: {
4
+ name: "i18n",
5
+ description: "Add internationalization (i18n) support to your plugin",
6
+ scriptPath: "./scripts/add-i18n.js"
7
+ }
8
+ }
9
+ };
10
+
11
+ export { defaultAdditions as default };
@@ -0,0 +1,48 @@
1
+ import { additionsDebug, printChanges } from './utils.js';
2
+ import defaultAdditions from './additions.js';
3
+ import { Context } from '../migrations/context.js';
4
+ import { gitCommitNoVerify } from '../utils/utils.git.js';
5
+ import { output } from '../utils/utils.console.js';
6
+ import { formatFiles, flushChanges, installNPMDependencies } from '../migrations/utils.js';
7
+
8
+ function getAvailableAdditions(additions = defaultAdditions.additions) {
9
+ return additions;
10
+ }
11
+ function getAdditionByName(name, additions = defaultAdditions.additions) {
12
+ return additions[name];
13
+ }
14
+ async function runAddition(addition, additionOptions = {}, runOptions = {}) {
15
+ const basePath = process.cwd();
16
+ output.log({
17
+ title: `Running addition: ${addition.name}`,
18
+ body: [addition.description]
19
+ });
20
+ try {
21
+ const context = new Context(basePath);
22
+ const updatedContext = await executeAddition(addition, context, additionOptions);
23
+ const shouldCommit = runOptions.commitChanges && updatedContext.hasChanges();
24
+ additionsDebug(`context for "${addition.name} (${addition.scriptPath})":`);
25
+ additionsDebug("%O", updatedContext.listChanges());
26
+ await formatFiles(updatedContext);
27
+ flushChanges(updatedContext);
28
+ printChanges(updatedContext, addition.name, addition);
29
+ installNPMDependencies(updatedContext);
30
+ if (shouldCommit) {
31
+ await gitCommitNoVerify(`chore: add ${addition.name} support via create-plugin`);
32
+ }
33
+ output.success({
34
+ title: `Successfully added ${addition.name} to your plugin.`
35
+ });
36
+ } catch (error) {
37
+ if (error instanceof Error) {
38
+ throw new Error(`Error running addition "${addition.name} (${addition.scriptPath})": ${error.message}`);
39
+ }
40
+ throw error;
41
+ }
42
+ }
43
+ async function executeAddition(addition, context, options = {}) {
44
+ const module = await import(addition.scriptPath);
45
+ return module.default(context, options);
46
+ }
47
+
48
+ export { executeAddition, getAdditionByName, getAvailableAdditions, runAddition };
@@ -0,0 +1,28 @@
1
+ export { addDependenciesToPackageJson, flushChanges, formatFiles, installNPMDependencies } from '../migrations/utils.js';
2
+ import chalk from 'chalk';
3
+ import { debug } from '../utils/utils.cli.js';
4
+ import { output } from '../utils/utils.console.js';
5
+
6
+ const additionsDebug = debug.extend("additions");
7
+ function printChanges(context, key, addition) {
8
+ const changes = context.listChanges();
9
+ const lines = [];
10
+ for (const [filePath, { changeType }] of Object.entries(changes)) {
11
+ if (changeType === "add") {
12
+ lines.push(`${chalk.green("ADD")} ${filePath}`);
13
+ } else if (changeType === "update") {
14
+ lines.push(`${chalk.yellow("UPDATE")} ${filePath}`);
15
+ } else if (changeType === "delete") {
16
+ lines.push(`${chalk.red("DELETE")} ${filePath}`);
17
+ }
18
+ }
19
+ output.addHorizontalLine("gray");
20
+ output.logSingleLine(`${key} (${addition.description})`);
21
+ if (lines.length === 0) {
22
+ output.logSingleLine("No changes were made");
23
+ } else {
24
+ output.log({ title: "Changes:", withPrefix: false, body: output.bulletList(lines) });
25
+ }
26
+ }
27
+
28
+ export { additionsDebug, printChanges };
package/dist/bin/run.js CHANGED
@@ -4,8 +4,9 @@ import { update } from '../commands/update.command.js';
4
4
  import { migrate } from '../commands/migrate.command.js';
5
5
  import { version } from '../commands/version.command.js';
6
6
  import { provisioning } from '../commands/provisioning.command.js';
7
- import { isUnsupportedPlatform } from '../utils/utils.os.js';
7
+ import { add } from '../commands/add.command.js';
8
8
  import { argv, commandName } from '../utils/utils.cli.js';
9
+ import { isUnsupportedPlatform } from '../utils/utils.os.js';
9
10
  import { output } from '../utils/utils.console.js';
10
11
 
11
12
  if (isUnsupportedPlatform()) {
@@ -21,7 +22,8 @@ const commands = {
21
22
  generate,
22
23
  update,
23
24
  version,
24
- provisioning
25
+ provisioning,
26
+ add
25
27
  };
26
28
  const command = commands[commandName] || "generate";
27
29
  command(argv);
@@ -0,0 +1,72 @@
1
+ import Enquirer from 'enquirer';
2
+ import { output } from '../../utils/utils.console.js';
3
+
4
+ const COMMON_LOCALES = [
5
+ { name: "en-US", message: "English (US)" },
6
+ { name: "es-ES", message: "Spanish (Spain)" },
7
+ { name: "fr-FR", message: "French (France)" },
8
+ { name: "de-DE", message: "German (Germany)" },
9
+ { name: "zh-Hans", message: "Chinese (Simplified)" },
10
+ { name: "pt-BR", message: "Portuguese (Brazil)" },
11
+ { name: "sv-SE", message: "Swedish (Sweden)" },
12
+ { name: "nl-NL", message: "Dutch (Netherlands)" },
13
+ { name: "ja-JP", message: "Japanese (Japan)" },
14
+ { name: "it-IT", message: "Italian (Italy)" }
15
+ ];
16
+ async function promptI18nOptions() {
17
+ const enquirer = new Enquirer();
18
+ output.log({
19
+ title: "Configure internationalization (i18n) for your plugin",
20
+ body: [
21
+ "Select the locales you want to support. At least one locale must be selected.",
22
+ "Use space to select, enter to continue."
23
+ ]
24
+ });
25
+ const localeChoices = COMMON_LOCALES.map((locale) => ({
26
+ name: locale.name,
27
+ message: locale.message,
28
+ value: locale.name
29
+ }));
30
+ let selectedLocales = [];
31
+ try {
32
+ const result = await enquirer.prompt({
33
+ type: "multiselect",
34
+ name: "locales",
35
+ message: "Select locales to support:",
36
+ choices: localeChoices,
37
+ initial: [0],
38
+ // Pre-select en-US by default
39
+ validate(value) {
40
+ if (value.length === 0) {
41
+ return "At least one locale must be selected";
42
+ }
43
+ return true;
44
+ }
45
+ });
46
+ selectedLocales = result.locales;
47
+ } catch (error) {
48
+ output.warning({ title: "Addition cancelled by user." });
49
+ process.exit(0);
50
+ }
51
+ try {
52
+ const addMoreResult = await enquirer.prompt({
53
+ type: "input",
54
+ name: "additionalLocales",
55
+ message: 'Enter additional locale codes (comma-separated, e.g., "ko-KR,ru-RU") or press enter to skip:'
56
+ });
57
+ const additionalLocalesInput = addMoreResult.additionalLocales;
58
+ if (additionalLocalesInput && additionalLocalesInput.trim()) {
59
+ const additionalLocales = additionalLocalesInput.split(",").map((locale) => locale.trim()).filter((locale) => locale.length > 0 && !selectedLocales.includes(locale));
60
+ selectedLocales.push(...additionalLocales);
61
+ }
62
+ } catch (error) {
63
+ }
64
+ output.log({
65
+ title: `Selected locales: ${selectedLocales.join(", ")}`
66
+ });
67
+ return {
68
+ locales: selectedLocales
69
+ };
70
+ }
71
+
72
+ export { promptI18nOptions };
@@ -0,0 +1,92 @@
1
+ import { getAvailableAdditions, getAdditionByName, runAddition } from '../additions/manager.js';
2
+ import { isGitDirectory, isGitDirectoryClean } from '../utils/utils.git.js';
3
+ import { isPluginDirectory } from '../utils/utils.plugin.js';
4
+ import { output } from '../utils/utils.console.js';
5
+ import { promptI18nOptions } from './add/prompts.js';
6
+
7
+ const add = async (argv) => {
8
+ const subCommand = argv._[1];
9
+ if (!subCommand) {
10
+ const availableAdditions = getAvailableAdditions();
11
+ const additionsList = Object.values(availableAdditions).map(
12
+ (addition2) => `${addition2.name} - ${addition2.description}`
13
+ );
14
+ output.error({
15
+ title: "No addition specified",
16
+ body: [
17
+ "Usage: npx @grafana/create-plugin add <addition-name>",
18
+ "",
19
+ "Available additions:",
20
+ ...output.bulletList(additionsList)
21
+ ]
22
+ });
23
+ process.exit(1);
24
+ }
25
+ await performPreAddChecks(argv);
26
+ const addition = getAdditionByName(subCommand);
27
+ if (!addition) {
28
+ const availableAdditions = getAvailableAdditions();
29
+ const additionsList = Object.values(availableAdditions).map((addition2) => addition2.name);
30
+ output.error({
31
+ title: `Unknown addition: ${subCommand}`,
32
+ body: ["Available additions:", ...output.bulletList(additionsList)]
33
+ });
34
+ process.exit(1);
35
+ }
36
+ try {
37
+ let options = {};
38
+ switch (addition.name) {
39
+ case "i18n":
40
+ options = await promptI18nOptions();
41
+ break;
42
+ default:
43
+ break;
44
+ }
45
+ const commitChanges = argv.commit;
46
+ await runAddition(addition, options, { commitChanges });
47
+ } catch (error) {
48
+ if (error instanceof Error) {
49
+ output.error({
50
+ title: "Addition failed",
51
+ body: [error.message]
52
+ });
53
+ }
54
+ process.exit(1);
55
+ }
56
+ };
57
+ async function performPreAddChecks(argv) {
58
+ if (!await isGitDirectory() && !argv.force) {
59
+ output.error({
60
+ title: "You are not inside a git directory",
61
+ body: [
62
+ `In order to proceed please run ${output.formatCode("git init")} in the root of your project and commit your changes.`,
63
+ `(This check is necessary to make sure that the changes are easy to revert and don't interfere with any changes you currently have.`,
64
+ `In case you want to proceed as is please use the ${output.formatCode("--force")} flag.)`
65
+ ]
66
+ });
67
+ process.exit(1);
68
+ }
69
+ if (!await isGitDirectoryClean() && !argv.force) {
70
+ output.error({
71
+ title: "Please clean your repository working tree before adding features.",
72
+ body: [
73
+ "Commit your changes or stash them.",
74
+ `(This check is necessary to make sure that the changes are easy to revert and don't mess with any changes you currently have.`,
75
+ `In case you want to proceed as is please use the ${output.formatCode("--force")} flag.)`
76
+ ]
77
+ });
78
+ process.exit(1);
79
+ }
80
+ if (!isPluginDirectory() && !argv.force) {
81
+ output.error({
82
+ title: "Are you inside a plugin directory?",
83
+ body: [
84
+ `We couldn't find a "src/plugin.json" file under your current directory.`,
85
+ `(Please make sure to run this command from the root of your plugin folder. In case you want to proceed as is please use the ${output.formatCode("--force")} flag.)`
86
+ ]
87
+ });
88
+ process.exit(1);
89
+ }
90
+ }
91
+
92
+ export { add };
package/dist/constants.js CHANGED
@@ -1,5 +1,5 @@
1
- import { fileURLToPath } from 'node:url';
2
1
  import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
3
 
4
4
  const __dirname = fileURLToPath(new URL(".", import.meta.url));
5
5
  const IS_DEV = process.env.CREATE_PLUGIN_DEV !== void 0;
@@ -32,10 +32,18 @@ const EXTRA_TEMPLATE_VARIABLES = {
32
32
  const DEFAULT_FEATURE_FLAGS = {
33
33
  useReactRouterV6: true,
34
34
  bundleGrafanaUI: false,
35
+ usePlaywright: true,
35
36
  useExperimentalRspack: false,
36
37
  useExperimentalUpdates: true
37
38
  };
38
- const GRAFANA_FE_PACKAGES = ["@grafana/data", "@grafana/runtime", "@grafana/schema", "@grafana/ui"];
39
+ const GRAFANA_FE_PACKAGES = [
40
+ "@grafana/data",
41
+ "@grafana/e2e-selectors",
42
+ "@grafana/e2e",
43
+ "@grafana/runtime",
44
+ "@grafana/schema",
45
+ "@grafana/ui"
46
+ ];
39
47
  const MIGRATION_CONFIG = {
40
48
  // Files that should be overriden during a migration.
41
49
  // (paths are relative to the scaffolded projects root)
@@ -1,11 +1,11 @@
1
- import { argv, commandName } from './utils.cli.js';
1
+ import fs from 'node:fs';
2
+ import { writeFile } from 'node:fs/promises';
3
+ import path from 'node:path';
2
4
  import { CURRENT_APP_VERSION } from './utils.version.js';
5
+ import { argv, commandName } from './utils.cli.js';
3
6
  import { DEFAULT_FEATURE_FLAGS } from '../constants.js';
4
- import fs from 'node:fs';
5
7
  import { output } from './utils.console.js';
6
8
  import { partitionArr } from './utils.helpers.js';
7
- import path from 'node:path';
8
- import { writeFile } from 'node:fs/promises';
9
9
 
10
10
  let hasShownConfigWarnings = false;
11
11
  function getConfig(workDir = process.cwd()) {
@@ -1,14 +1,15 @@
1
- import { DEFAULT_FEATURE_FLAGS, EXTRA_TEMPLATE_VARIABLES, PLUGIN_TYPES, TEMPLATE_PATHS, EXPORT_PATH_PREFIX } from '../constants.js';
1
+ import { lt } from 'semver';
2
+ import { glob } from 'glob';
3
+ import path from 'node:path';
4
+ import fs from 'node:fs';
2
5
  import { isFile, getExportFileName, filterOutCommonFiles, isFileStartingWith } from './utils.files.js';
3
- import { getPackageManagerFromUserAgent, getPackageManagerInstallCmd, getPackageManagerWithFallback } from './utils.packageManager.js';
4
6
  import { normalizeId, renderHandlebarsTemplate } from './utils.handlebars.js';
5
- import { CURRENT_APP_VERSION } from './utils.version.js';
7
+ import { getPluginJson } from './utils.plugin.js';
6
8
  import { debug } from './utils.cli.js';
7
- import fs from 'node:fs';
9
+ import { DEFAULT_FEATURE_FLAGS, EXTRA_TEMPLATE_VARIABLES, PLUGIN_TYPES, TEMPLATE_PATHS, EXPORT_PATH_PREFIX } from '../constants.js';
10
+ import { getPackageManagerFromUserAgent, getPackageManagerInstallCmd, getPackageManagerWithFallback } from './utils.packageManager.js';
11
+ import { getGrafanaRuntimeVersion, CURRENT_APP_VERSION } from './utils.version.js';
8
12
  import { getConfig } from './utils.config.js';
9
- import { getPluginJson } from './utils.plugin.js';
10
- import { glob } from 'glob';
11
- import path from 'node:path';
12
13
 
13
14
  const templatesDebugger = debug.extend("templates");
14
15
  function getTemplateFiles(pluginType, filter) {
@@ -56,6 +57,9 @@ function renderTemplateFromFile(templateFile, data) {
56
57
  function getTemplateData(cliArgs) {
57
58
  const { features } = getConfig();
58
59
  const currentVersion = CURRENT_APP_VERSION;
60
+ const grafanaVersion = getGrafanaRuntimeVersion();
61
+ const usePlaywright = features.usePlaywright === true || isFile(path.join(process.cwd(), "playwright.config.ts"));
62
+ const useCypress = !usePlaywright && lt(grafanaVersion, "11.0.0") && fs.existsSync(path.join(process.cwd(), "cypress"));
59
63
  const bundleGrafanaUI = features.bundleGrafanaUI ?? DEFAULT_FEATURE_FLAGS.bundleGrafanaUI;
60
64
  const getReactRouterVersion = () => features.useReactRouterV6 ? "6.22.0" : "5.2.0";
61
65
  const isAppType = (pluginType) => pluginType === PLUGIN_TYPES.app || pluginType === PLUGIN_TYPES.scenes;
@@ -82,6 +86,8 @@ function getTemplateData(cliArgs) {
82
86
  useReactRouterV6: features.useReactRouterV6 ?? DEFAULT_FEATURE_FLAGS.useReactRouterV6,
83
87
  reactRouterVersion: getReactRouterVersion(),
84
88
  scenesVersion: features.useReactRouterV6 ? "^6.10.4" : "^5.41.3",
89
+ usePlaywright,
90
+ useCypress,
85
91
  useExperimentalRspack: Boolean(features.useExperimentalRspack),
86
92
  frontendBundler
87
93
  };
@@ -105,6 +111,8 @@ function getTemplateData(cliArgs) {
105
111
  useReactRouterV6: features.useReactRouterV6 ?? DEFAULT_FEATURE_FLAGS.useReactRouterV6,
106
112
  reactRouterVersion: getReactRouterVersion(),
107
113
  scenesVersion: features.useReactRouterV6 ? "^6.10.4" : "^5.41.3",
114
+ usePlaywright,
115
+ useCypress,
108
116
  pluginExecutable: pluginJson.executable,
109
117
  useExperimentalRspack: Boolean(features.useExperimentalRspack),
110
118
  frontendBundler
@@ -1,8 +1,14 @@
1
- import 'node:fs';
2
- import 'node:path';
1
+ import { readFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
3
  import { getVersion } from '../libs/version/src/index.js';
4
- import '../constants.js';
4
+ import { TEMPLATE_PATHS } from '../constants.js';
5
5
 
6
6
  const CURRENT_APP_VERSION = getVersion();
7
+ function getGrafanaRuntimeVersion() {
8
+ const packageJsonPath = path.join(TEMPLATE_PATHS.common, "_package.json");
9
+ const pkg = readFileSync(packageJsonPath, "utf8");
10
+ const { version } = /\"(@grafana\/runtime)\":\s\"\^(?<version>.*)\"/.exec(pkg)?.groups ?? {};
11
+ return version;
12
+ }
7
13
 
8
- export { CURRENT_APP_VERSION };
14
+ export { CURRENT_APP_VERSION, getGrafanaRuntimeVersion };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafana/create-plugin",
3
- "version": "6.1.1-canary.2232.18584719214.0",
3
+ "version": "6.2.0-canary.2233.18586197736.0",
4
4
  "repository": {
5
5
  "directory": "packages/create-plugin",
6
6
  "url": "https://github.com/grafana/plugin-tools"
@@ -61,5 +61,5 @@
61
61
  "engines": {
62
62
  "node": ">=20"
63
63
  },
64
- "gitHead": "8597c9484a3e5a450316a4c12d40485e730ebb4b"
64
+ "gitHead": "0e9c9708ed87727b5956b44fcdaa3bbc0d8221f8"
65
65
  }
@@ -0,0 +1,19 @@
1
+ export type AdditionMeta = {
2
+ name: string;
3
+ description: string;
4
+ scriptPath: string;
5
+ };
6
+
7
+ type Additions = {
8
+ additions: Record<string, AdditionMeta>;
9
+ };
10
+
11
+ export default {
12
+ additions: {
13
+ i18n: {
14
+ name: 'i18n',
15
+ description: 'Add internationalization (i18n) support to your plugin',
16
+ scriptPath: './scripts/add-i18n.js',
17
+ },
18
+ },
19
+ } as Additions;
@@ -0,0 +1,77 @@
1
+ import { additionsDebug, flushChanges, formatFiles, installNPMDependencies, printChanges } from './utils.js';
2
+ import defaultAdditions, { AdditionMeta } from './additions.js';
3
+
4
+ import { Context } from '../migrations/context.js';
5
+ import { gitCommitNoVerify } from '../utils/utils.git.js';
6
+ import { output } from '../utils/utils.console.js';
7
+
8
+ export type AdditionFn = (context: Context, options?: AdditionOptions) => Context | Promise<Context>;
9
+
10
+ export type AdditionOptions = Record<string, any>;
11
+
12
+ type RunAdditionOptions = {
13
+ commitChanges?: boolean;
14
+ };
15
+
16
+ export function getAvailableAdditions(
17
+ additions: Record<string, AdditionMeta> = defaultAdditions.additions
18
+ ): Record<string, AdditionMeta> {
19
+ return additions;
20
+ }
21
+
22
+ export function getAdditionByName(
23
+ name: string,
24
+ additions: Record<string, AdditionMeta> = defaultAdditions.additions
25
+ ): AdditionMeta | undefined {
26
+ return additions[name];
27
+ }
28
+
29
+ export async function runAddition(
30
+ addition: AdditionMeta,
31
+ additionOptions: AdditionOptions = {},
32
+ runOptions: RunAdditionOptions = {}
33
+ ): Promise<void> {
34
+ const basePath = process.cwd();
35
+
36
+ output.log({
37
+ title: `Running addition: ${addition.name}`,
38
+ body: [addition.description],
39
+ });
40
+
41
+ try {
42
+ const context = new Context(basePath);
43
+ const updatedContext = await executeAddition(addition, context, additionOptions);
44
+ const shouldCommit = runOptions.commitChanges && updatedContext.hasChanges();
45
+
46
+ additionsDebug(`context for "${addition.name} (${addition.scriptPath})":`);
47
+ additionsDebug('%O', updatedContext.listChanges());
48
+
49
+ await formatFiles(updatedContext);
50
+ flushChanges(updatedContext);
51
+ printChanges(updatedContext, addition.name, addition);
52
+
53
+ installNPMDependencies(updatedContext);
54
+
55
+ if (shouldCommit) {
56
+ await gitCommitNoVerify(`chore: add ${addition.name} support via create-plugin`);
57
+ }
58
+
59
+ output.success({
60
+ title: `Successfully added ${addition.name} to your plugin.`,
61
+ });
62
+ } catch (error) {
63
+ if (error instanceof Error) {
64
+ throw new Error(`Error running addition "${addition.name} (${addition.scriptPath})": ${error.message}`);
65
+ }
66
+ throw error;
67
+ }
68
+ }
69
+
70
+ export async function executeAddition(
71
+ addition: AdditionMeta,
72
+ context: Context,
73
+ options: AdditionOptions = {}
74
+ ): Promise<Context> {
75
+ const module: { default: AdditionFn } = await import(addition.scriptPath);
76
+ return module.default(context, options);
77
+ }