sammi-next 1.5.2 → 1.5.3

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/node/cli.mjs CHANGED
@@ -5,10 +5,11 @@ import colors from "picocolors";
5
5
  import chokidar from "chokidar";
6
6
  import { build } from "tsdown";
7
7
  import { fileURLToPath } from "node:url";
8
+ import lodash from "lodash";
8
9
  import Ajv from "ajv";
9
10
 
10
11
  //#region package.json
11
- var version = "1.5.1";
12
+ var version = "1.5.2";
12
13
 
13
14
  //#endregion
14
15
  //#region src/node/constants.ts
@@ -89,10 +90,9 @@ function generatePreview(options) {
89
90
  const js_script = fs.readFileSync(path.join(rootDir, config.out.dir, config.out.js), "utf-8");
90
91
  return fs.readFileSync(path.join(SAMMI_NEXT_PACKAGE_DIR, ".sammi", "preview.blueprint.html"), "utf-8").replace(/{{EXTERNAL}}/g, external ? `<div id="${config.id}-external">${external}</div>` : "").replace(/{{SCRIPT}}/g, js_script);
91
92
  }
92
- async function buildOnce(options) {
93
+ function mergeBuilderOptions(options) {
93
94
  const { config, rootDir, mode } = options;
94
- const startTime = Date.now();
95
- const bundle = await build({
95
+ const default_build_config = {
96
96
  entry: [config.entry],
97
97
  outDir: path.join(rootDir, config.out.dir),
98
98
  platform: "browser",
@@ -108,7 +108,13 @@ async function buildOnce(options) {
108
108
  name: `${GLOBAL_NAME}.${config.id}`,
109
109
  exports: "named"
110
110
  }
111
- });
111
+ };
112
+ return lodash.merge(default_build_config, options.config.tsdownConfig);
113
+ }
114
+ async function buildOnce(options) {
115
+ const { config, rootDir } = options;
116
+ const startTime = Date.now();
117
+ const bundle = await build(options.config.tsdownConfig);
112
118
  const tsdownTime = Date.now();
113
119
  console.info(GREEN_CHECK, BUILD_PREFIX, `built ${config.out.js} in ${displayTime(tsdownTime - startTime)}`);
114
120
  fs.writeFileSync(path.join(rootDir, config.out.dir, config.out.sef), generateSEF(options), "utf-8");
@@ -246,6 +252,12 @@ const configValidator = ajv.compile({
246
252
  required: [],
247
253
  nullable: true,
248
254
  additionalProperties: false
255
+ },
256
+ tsdownConfig: {
257
+ type: "object",
258
+ required: [],
259
+ nullable: true,
260
+ additionalProperties: true
249
261
  }
250
262
  },
251
263
  required: [
@@ -254,7 +266,7 @@ const configValidator = ajv.compile({
254
266
  "version",
255
267
  "entry"
256
268
  ],
257
- additionalProperties: false
269
+ additionalProperties: true
258
270
  });
259
271
  async function loadConfig(rootDir) {
260
272
  for (const ext of DEFAULT_CONFIG_EXTENSIONS) {
@@ -299,7 +311,8 @@ function resolveExtensionConfig(config, rootDir) {
299
311
  dir: config.out?.dir || "dist",
300
312
  js: config.out?.js || "extension.js",
301
313
  sef: config.out?.sef || "extension.sef"
302
- }
314
+ },
315
+ tsdownConfig: config.tsdownConfig || {}
303
316
  };
304
317
  if (!fs.existsSync(resolved.entry)) throw new Error(`Entry file not found: ${resolved.entry}`);
305
318
  if (resolved.external && !fs.existsSync(resolved.external)) throw new Error(`External file not found: ${resolved.external}`);
@@ -317,11 +330,13 @@ async function resolveBuildConfig(root, command, build_cli) {
317
330
  config.out.dir = build_cli.outDir ?? config.out.dir;
318
331
  config.out.js = build_cli.outJs ?? config.out.js;
319
332
  config.out.sef = build_cli.outSef ?? config.out.sef;
320
- return {
333
+ const resolved = {
321
334
  rootDir,
322
335
  mode,
323
336
  config: resolveExtensionConfig(config, rootDir)
324
337
  };
338
+ resolved.config.tsdownConfig = mergeBuilderOptions(resolved);
339
+ return resolved;
325
340
  }
326
341
 
327
342
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":["path","VERSION","res","VERSION"],"sources":["../../package.json","../../src/node/constants.ts","../../src/node/utils.ts","../../src/node/build.ts","../../src/node/config.ts","../../src/node/cli.ts"],"sourcesContent":["","import path from 'node:path';\r\nimport { fileURLToPath } from 'node:url';\r\nimport colors from 'picocolors'\r\n\r\nexport { version as VERSION } from '../../package.json';\r\n\r\nexport const DEFAULT_CONFIG_EXTENSIONS: string[] = [\r\n '.mjs',\r\n '.js',\r\n '.mts',\r\n '.ts',\r\n]\r\n\r\nexport const GLOBAL_NAME = \"SAMMIExtensions\";\r\n\r\nexport const BUILD_PREFIX = colors.blue(\"[sammi-next]\");\r\nexport const GREEN_CHECK = colors.green('✔');\r\nexport const RED_X = colors.red('✗');\r\n\r\nfunction findPackageDir() {\r\n let initPath = fileURLToPath(import.meta.url);\r\n while (!initPath.endsWith('sammi-next')) {\r\n initPath = path.resolve(initPath, '..');\r\n }\r\n return initPath;\r\n}\r\nexport const SAMMI_NEXT_PACKAGE_DIR = findPackageDir();\r\n","export function displayTime(time: number): string {\r\n if (time < 1_000)\r\n return `${time}ms`;\r\n\r\n time = time / 1_000;\r\n\r\n if (time < 60)\r\n return `${time.toFixed(2)}s`\r\n\r\n const mins = Math.floor(time / 60);\r\n const seconds = Math.round(time % 60);\r\n\r\n if (seconds === 60)\r\n return `${mins + 1}m`\r\n\r\n return `${mins}m${seconds < 1 ? '' : ` ${seconds}s`}`;\r\n}\r\n","import fs from 'node:fs';\r\nimport path from 'node:path';\r\nimport colors from 'picocolors';\r\nimport chokidar from 'chokidar';\r\nimport { ResolvedExtensionConfig } from \"@shared/config-types\";\r\nimport { build, TsdownBundle } from \"tsdown\";\r\nimport { BUILD_PREFIX, GLOBAL_NAME, GREEN_CHECK, RED_X, SAMMI_NEXT_PACKAGE_DIR, VERSION } from \"./constants\";\r\nimport { displayTime } from './utils';\r\n// import nodePolyfills from '@rolldown/plugin-node-polyfills';\r\n\r\nexport enum BuildMode {\r\n DEV,\r\n PRODUCTION,\r\n}\r\n\r\nexport const BuildModes = Object.keys(BuildMode).filter(key => isNaN(Number(key)));\r\n\r\nexport interface BuildOptions {\r\n config: ResolvedExtensionConfig;\r\n rootDir: string;\r\n mode?: BuildMode;\r\n}\r\n\r\nexport type ResolvedBuildOptions = Required<BuildOptions>;\r\n\r\nfunction readOptionalFile(path: string): string | undefined {\r\n if (!fs.existsSync(path)) return;\r\n\r\n return fs.readFileSync(path, 'utf-8');\r\n}\r\n\r\nconst CommandRE = /\\w+\\(\\w+,\\s*{\\s*default:/gm;\r\n\r\nfunction generateSEF(options: ResolvedBuildOptions): string {\r\n const { config, rootDir, mode } = options;\r\n const content = [];\r\n\r\n const required_files: {\r\n header: string,\r\n content: string,\r\n }[] = [\r\n {\r\n header: \"extension_name\",\r\n content: config.name,\r\n },\r\n {\r\n header: \"extension_info\",\r\n content: config.info,\r\n },\r\n {\r\n header: \"extension_version\",\r\n content: config.version,\r\n },\r\n ]\r\n\r\n for (const field of required_files) {\r\n content.push(`[${field.header}]`, field.content, \"\");\r\n }\r\n\r\n const external = readOptionalFile(config.external);\r\n content.push(\"[insert_external]\", external ? `<div id=\"${config.id}-external\">${external}</div>` : \"\", \"\");\r\n\r\n const js_script = fs.readFileSync(path.join(rootDir, config.out.dir, config.out.js), \"utf-8\");\r\n content.push(\"[insert_command]\", CommandRE.test(js_script) ? `${GLOBAL_NAME}.${config.id}.default()` : \"\", \"\");\r\n content.push(\"[insert_hook]\", \"\", \"\") // TODO: maybe add hook retro-compatibility\r\n content.push(\"[insert_script]\", js_script, \"\");\r\n\r\n let over = readOptionalFile(config.over);\r\n if (over && mode === BuildMode.PRODUCTION) {\r\n over = JSON.stringify(JSON.parse(over));\r\n }\r\n content.push(\"[insert_over]\", over && over != \"{}\" ? over : \"\", \"\");\r\n return content.join(\"\\n\");\r\n}\r\n\r\nfunction generatePreview(options: ResolvedBuildOptions): string {\r\n const { config, rootDir } = options;\r\n\r\n const external = readOptionalFile(config.external);\r\n const js_script = fs.readFileSync(path.join(rootDir, config.out.dir, config.out.js), \"utf-8\");\r\n return fs\r\n .readFileSync(path.join(SAMMI_NEXT_PACKAGE_DIR, \".sammi\", \"preview.blueprint.html\"), \"utf-8\")\r\n .replace(/{{EXTERNAL}}/g, external ? `<div id=\"${config.id}-external\">${external}</div>` : \"\")\r\n .replace(/{{SCRIPT}}/g, js_script);\r\n}\r\n\r\nasync function buildOnce(options: ResolvedBuildOptions) {\r\n const { config, rootDir, mode } = options;\r\n\r\n const startTime = Date.now();\r\n const bundle = await build({\r\n entry: [config.entry],\r\n outDir: path.join(rootDir, config.out.dir),\r\n platform: 'browser',\r\n format: 'iife',\r\n target: ['es2022'],\r\n sourcemap: false,\r\n minify: mode === BuildMode.PRODUCTION,\r\n banner: {\r\n js: `/* ${config.name} v${config.version} - Built with SAMMI Next v${VERSION} */`,\r\n },\r\n noExternal: ['**'],\r\n outputOptions: {\r\n entryFileNames: config.out.js,\r\n extend: true,\r\n name: `${GLOBAL_NAME}.${config.id}`,\r\n exports: 'named',\r\n },\r\n // plugins: [\r\n // nodePolyfills(),\r\n // ],\r\n });\r\n const tsdownTime = Date.now();\r\n console.info(GREEN_CHECK, BUILD_PREFIX, `built ${config.out.js} in ${displayTime(tsdownTime - startTime)}`);\r\n\r\n fs.writeFileSync(path.join(rootDir, config.out.dir, config.out.sef), generateSEF(options), 'utf-8');\r\n const sefTime = Date.now();\r\n console.info(GREEN_CHECK, BUILD_PREFIX, `built ${config.out.sef} in ${displayTime(sefTime - tsdownTime)}`);\r\n\r\n fs.writeFileSync(path.join(rootDir, config.out.dir, \"preview.html\"), generatePreview(options), 'utf-8');\r\n const previewTime = Date.now();\r\n console.info(GREEN_CHECK, BUILD_PREFIX, `built preview.html in ${displayTime(previewTime - sefTime)}`);\r\n return { bundle, startTime };\r\n}\r\n\r\nexport async function buildExtension(options: ResolvedBuildOptions) {\r\n const { config, mode } = options;\r\n\r\n console.info(\r\n colors.cyan(\r\n `SAMMI Next v${VERSION} ${colors.green(\r\n `building \"${config.name}\" extension in ${BuildMode[mode].toLowerCase()} mode...`\r\n )}`\r\n ),\r\n );\r\n\r\n let bundle: TsdownBundle[] | undefined;\r\n let startTime: number | undefined;\r\n\r\n try {\r\n const res = await buildOnce(options);\r\n bundle = res.bundle;\r\n startTime = res.startTime;\r\n\r\n if (options.mode !== BuildMode.DEV) return bundle;\r\n\r\n console.info(BUILD_PREFIX, colors.cyan(\"watching for file changes...\"));\r\n\r\n const watchPaths = [\r\n path.dirname(config.entry),\r\n config.external,\r\n config.over,\r\n ].filter(Boolean);\r\n\r\n const watcher = chokidar.watch(watchPaths, { ignoreInitial: true });\r\n let timer: NodeJS.Timeout | null = null;\r\n\r\n watcher.on('all', (event, p) => {\r\n console.info(colors.cyan(`${event}: ${p}`));\r\n if (timer)\r\n clearTimeout(timer);\r\n\r\n timer = setTimeout(() => {\r\n buildOnce(options).then(res => {\r\n bundle = res.bundle;\r\n startTime = res.startTime;\r\n }).catch(e => console.error(e));\r\n }, 100);\r\n });\r\n\r\n process.on('SIGINT', () => {\r\n console.info(\"\\nStopping watch mode...\");\r\n watcher\r\n .close()\r\n .then(() => process.exit(0))\r\n .catch(e => {\r\n console.error(e);\r\n process.exit(1);\r\n });\r\n });\r\n return watcher;\r\n } catch (error) {\r\n if (startTime) {\r\n console.error(RED_X, BUILD_PREFIX, `Build failed in ${displayTime(Date.now() - startTime)}`);\r\n startTime = undefined;\r\n }\r\n throw error;\r\n }\r\n}\r\n","\r\n\r\nimport { ExtensionConfig, ResolvedExtensionConfig } from \"@shared/config-types\";\r\nimport Ajv, { JSONSchemaType } from \"ajv\";\r\nimport fs from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { DEFAULT_CONFIG_EXTENSIONS } from \"./constants\";\r\nimport { BuildCLIOptions } from \"./cli\";\r\nimport { BuildModes, ResolvedBuildOptions } from \"./build\";\r\n\r\nconst ajv = new Ajv();\r\n\r\najv.addKeyword({\r\n keyword: \"fileExists\",\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n validate: (_schema: any, data: any) => {\r\n if (!data) return true;\r\n\r\n return fs.existsSync(data as string);\r\n },\r\n errors: false\r\n});\r\n\r\nconst schema: JSONSchemaType<ExtensionConfig> = {\r\n type: \"object\",\r\n properties: {\r\n id: {\r\n type: \"string\",\r\n minLength: 1,\r\n pattern: \"^[a-zA-Z0-9-_]+$\",\r\n },\r\n name: {\r\n type: \"string\",\r\n minLength: 1,\r\n pattern: \"^[a-zA-Z0-9 -_]+$\",\r\n },\r\n info: {\r\n type: \"string\",\r\n default: \"\",\r\n nullable: true,\r\n },\r\n version: {\r\n type: \"string\",\r\n minLength: 1,\r\n pattern: \"^\\\\d+(?:\\\\.\\\\d+)*(?:-.*)?$\",\r\n },\r\n entry: {\r\n type: \"string\",\r\n minLength: 1,\r\n fileExists: true,\r\n },\r\n external: {\r\n type: \"string\",\r\n minLength: 1,\r\n fileExists: true,\r\n nullable: true,\r\n },\r\n over: {\r\n type: \"string\",\r\n minLength: 1,\r\n fileExists: true,\r\n nullable: true,\r\n },\r\n out: {\r\n type: \"object\",\r\n properties: {\r\n dir: {\r\n type: \"string\",\r\n minLength: 1,\r\n pattern: \"^[^<>:\\\"|?*]+$\",\r\n default: \"dist\",\r\n nullable: true,\r\n },\r\n js: {\r\n type: \"string\",\r\n minLength: 4,\r\n pattern: \"^[\\\\w\\\\-. ]+\\\\.js$\",\r\n default: \"extension.js\",\r\n nullable: true,\r\n },\r\n sef: {\r\n type: \"string\",\r\n minLength: 5,\r\n pattern: \"^[\\\\w\\\\-. ]+\\\\.sef$\",\r\n default: \"extension.sef\",\r\n nullable: true,\r\n }\r\n },\r\n required: [],\r\n nullable: true,\r\n additionalProperties: false,\r\n }\r\n },\r\n required: [\"name\", \"id\", \"version\", \"entry\"],\r\n additionalProperties: false,\r\n};\r\n\r\nconst configValidator = ajv.compile(schema);\r\n\r\nexport async function loadConfig(rootDir: string) {\r\n for (const ext of DEFAULT_CONFIG_EXTENSIONS) {\r\n const configPath = path.join(rootDir, `sammi.config${ext}`);\r\n\r\n if (!fs.existsSync(configPath)) continue;\r\n\r\n try {\r\n const { createJiti } = await import('jiti');\r\n const jiti = createJiti(rootDir, {\r\n interopDefault: true,\r\n moduleCache: true,\r\n });\r\n\r\n const config = await jiti.import(configPath, { default: true });\r\n\r\n return validateExtensionConfig(config, configPath);\r\n } catch (error) {\r\n throw new Error(`Error loading ${configPath}: ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n }\r\n\r\n const jsonPath = path.join(rootDir, 'sammi.config.json');\r\n if (fs.existsSync(jsonPath)) {\r\n try {\r\n const raw = fs.readFileSync(jsonPath, 'utf-8');\r\n const config = JSON.parse(raw) as unknown;\r\n return validateExtensionConfig(config, jsonPath);\r\n } catch (error) {\r\n throw new Error(`Error loading ${jsonPath}: ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n }\r\n\r\n throw new Error('SAMMI Next extension config file not found in the root dir.');\r\n}\r\n\r\n\r\nfunction validateExtensionConfig(config: unknown, configPath: string): ExtensionConfig {\r\n if (!configValidator(config)) {\r\n const errors = configValidator.errors?.map(err => ` - ${err.instancePath} ${err.message}`).join('\\n');\r\n throw new Error(`Invalid config from ${configPath}:\\n${errors}`);\r\n }\r\n\r\n return config;\r\n}\r\n\r\nexport function resolveExtensionConfig(config: ExtensionConfig, rootDir: string): ResolvedExtensionConfig {\r\n const resolved: ResolvedExtensionConfig = {\r\n id: config.id,\r\n name: config.name,\r\n version: config.version,\r\n info: config.info || '',\r\n entry: path.resolve(rootDir, config.entry),\r\n external: config.external ? path.resolve(rootDir, config.external) : '',\r\n over: config.over ? path.resolve(rootDir, config.over) : '',\r\n out: {\r\n dir: config.out?.dir || 'dist',\r\n js: config.out?.js || 'extension.js',\r\n sef: config.out?.sef || 'extension.sef',\r\n },\r\n };\r\n\r\n if (!fs.existsSync(resolved.entry))\r\n throw new Error(`Entry file not found: ${resolved.entry}`);\r\n\r\n if (resolved.external && !fs.existsSync(resolved.external))\r\n throw new Error(`External file not found: ${resolved.external}`);\r\n\r\n if (resolved.over && !fs.existsSync(resolved.over))\r\n throw new Error(`Over file not found: ${resolved.over}`);\r\n\r\n return resolved;\r\n}\r\n\r\nexport async function resolveBuildConfig(\r\n root: string | undefined,\r\n command: string,\r\n build_cli: BuildCLIOptions,\r\n) {\r\n const mode = BuildModes.findIndex(m => {\r\n return m.toLowerCase() === command.toLowerCase();\r\n });\r\n if (mode < 0)\r\n throw new Error(`Invalid mode: ${command}. It must be one of: ${BuildModes.join(', ')}`);\r\n\r\n const rootDir = root ?? process.cwd();\r\n const config = await loadConfig(rootDir);\r\n\r\n config.out ??= {};\r\n\r\n config.out.dir = build_cli.outDir ?? config.out.dir;\r\n config.out.js = build_cli.outJs ?? config.out.js;\r\n config.out.sef = build_cli.outSef ?? config.out.sef;\r\n\r\n const resolvedConfig = resolveExtensionConfig(config, rootDir);\r\n\r\n const resolved: ResolvedBuildOptions = {\r\n rootDir,\r\n mode,\r\n config: resolvedConfig\r\n }\r\n return resolved;\r\n}\r\n","import cac from \"cac\";\r\nimport { buildExtension, BuildMode } from \"./build\";\r\nimport colors from 'picocolors';\r\nimport { resolveBuildConfig } from \"./config\";\r\nimport { VERSION } from \"./constants\";\r\n\r\nconst cli = cac('sammi-next');\r\n\r\nexport interface GlobalCLIOptions {\r\n m?: string\r\n mode?: string\r\n}\r\n\r\nconst filterDuplicateOptions = <T extends object>(options: T) => {\r\n for (const [key, value] of Object.entries(options)) {\r\n if (!Array.isArray(value)) continue;\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\r\n options[key as keyof T] = value[value.length - 1];\r\n }\r\n};\r\n\r\nfunction cleanGlobalCLIOptions<Options extends GlobalCLIOptions>(options: Options): Omit<Options, keyof GlobalCLIOptions> {\r\n const ret = { ...options };\r\n delete ret.m\r\n delete ret.mode\r\n\r\n return ret;\r\n}\r\n\r\ncli.option('-m, --mode <mode>', '[string] set build mode');\r\n\r\nexport interface BuildCLIOptions {\r\n outDir?: string\r\n outJs?: string\r\n outSef?: string\r\n}\r\n\r\ncli\r\n .command('[root]', 'build extension')\r\n .option('--outDir <dir>', '[string] output directory (default: \"dist\")')\r\n .option('--outJs <name>', '[string] output file name for the JS (default: extension.js)')\r\n .option('--outSef <name>', '[string] output file name for the SEF (default: extension.sef)')\r\n .action(\r\n async (\r\n root: string | undefined,\r\n options: GlobalCLIOptions,\r\n ) => {\r\n filterDuplicateOptions(options);\r\n\r\n const buildOptions: BuildCLIOptions = cleanGlobalCLIOptions(options);\r\n\r\n try {\r\n const buildConfig = await resolveBuildConfig(\r\n root,\r\n options.mode || BuildMode[BuildMode.PRODUCTION],\r\n buildOptions,\r\n );\r\n\r\n await buildExtension(buildConfig);\r\n } catch (e) {\r\n const error = e as Error;\r\n console.error(colors.red(`error during build:\\n${error.stack}`));\r\n process.exit(1);\r\n }\r\n }\r\n )\r\n\r\ncli\r\n .command('dev [root]', 'build extension in dev mode')\r\n .option('--outDir <dir>', '[string] output directory (default: \"dist\")')\r\n .option('--outJs <name>', '[string] output file name for the JS (default: extension.js)')\r\n .option('--outSef <name>', '[string] output file name for the SEF (default: extension.sef)')\r\n .action(\r\n async (\r\n root: string | undefined,\r\n options: GlobalCLIOptions,\r\n ) => {\r\n filterDuplicateOptions(options);\r\n\r\n const buildOptions: BuildCLIOptions = cleanGlobalCLIOptions(options);\r\n\r\n try {\r\n const buildConfig = await resolveBuildConfig(\r\n root,\r\n options.mode || BuildMode[BuildMode.DEV],\r\n buildOptions,\r\n );\r\n\r\n await buildExtension(buildConfig);\r\n } catch (e) {\r\n const error = e as Error;\r\n console.error(colors.red(`error during build:\\n${error.stack}`));\r\n process.exit(1);\r\n }\r\n }\r\n )\r\n\r\ncli.help();\r\ncli.version(VERSION);\r\n\r\ncli.parse();\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.mjs","names":["path","VERSION","res","VERSION"],"sources":["../../package.json","../../src/node/constants.ts","../../src/node/utils.ts","../../src/node/build.ts","../../src/node/config.ts","../../src/node/cli.ts"],"sourcesContent":["","import path from 'node:path';\r\nimport { fileURLToPath } from 'node:url';\r\nimport colors from 'picocolors'\r\n\r\nexport { version as VERSION } from '../../package.json';\r\n\r\nexport const DEFAULT_CONFIG_EXTENSIONS: string[] = [\r\n '.mjs',\r\n '.js',\r\n '.mts',\r\n '.ts',\r\n]\r\n\r\nexport const GLOBAL_NAME = \"SAMMIExtensions\";\r\n\r\nexport const BUILD_PREFIX = colors.blue(\"[sammi-next]\");\r\nexport const GREEN_CHECK = colors.green('✔');\r\nexport const RED_X = colors.red('✗');\r\n\r\nfunction findPackageDir() {\r\n let initPath = fileURLToPath(import.meta.url);\r\n while (!initPath.endsWith('sammi-next')) {\r\n initPath = path.resolve(initPath, '..');\r\n }\r\n return initPath;\r\n}\r\nexport const SAMMI_NEXT_PACKAGE_DIR = findPackageDir();\r\n","export function displayTime(time: number): string {\r\n if (time < 1_000)\r\n return `${time}ms`;\r\n\r\n time = time / 1_000;\r\n\r\n if (time < 60)\r\n return `${time.toFixed(2)}s`\r\n\r\n const mins = Math.floor(time / 60);\r\n const seconds = Math.round(time % 60);\r\n\r\n if (seconds === 60)\r\n return `${mins + 1}m`\r\n\r\n return `${mins}m${seconds < 1 ? '' : ` ${seconds}s`}`;\r\n}\r\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport colors from 'picocolors';\nimport chokidar from 'chokidar';\nimport { ResolvedExtensionConfig } from \"@shared/config-types\";\nimport { build, InlineConfig as TsdownConfig, TsdownBundle } from \"tsdown\";\nimport { BUILD_PREFIX, GLOBAL_NAME, GREEN_CHECK, RED_X, SAMMI_NEXT_PACKAGE_DIR, VERSION } from \"./constants\";\nimport { displayTime } from './utils';\nimport lodash from 'lodash';\n// import nodePolyfills from '@rolldown/plugin-node-polyfills';\n\nexport enum BuildMode {\n DEV,\n PRODUCTION,\n}\n\nexport const BuildModes = Object.keys(BuildMode).filter(key => isNaN(Number(key)));\n\nexport interface BuildOptions {\n config: ResolvedExtensionConfig;\n rootDir: string;\n mode?: BuildMode;\n}\n\nexport type ResolvedBuildOptions = Required<BuildOptions>;\n\nfunction readOptionalFile(path: string): string | undefined {\n if (!fs.existsSync(path)) return;\n\n return fs.readFileSync(path, 'utf-8');\n}\n\nconst CommandRE = /\\w+\\(\\w+,\\s*{\\s*default:/gm;\n\nfunction generateSEF(options: ResolvedBuildOptions): string {\n const { config, rootDir, mode } = options;\n const content = [];\n\n const required_files: {\n header: string,\n content: string,\n }[] = [\n {\n header: \"extension_name\",\n content: config.name,\n },\n {\n header: \"extension_info\",\n content: config.info,\n },\n {\n header: \"extension_version\",\n content: config.version,\n },\n ]\n\n for (const field of required_files) {\n content.push(`[${field.header}]`, field.content, \"\");\n }\n\n const external = readOptionalFile(config.external);\n content.push(\"[insert_external]\", external ? `<div id=\"${config.id}-external\">${external}</div>` : \"\", \"\");\n\n const js_script = fs.readFileSync(path.join(rootDir, config.out.dir, config.out.js), \"utf-8\");\n content.push(\"[insert_command]\", CommandRE.test(js_script) ? `${GLOBAL_NAME}.${config.id}.default()` : \"\", \"\");\n content.push(\"[insert_hook]\", \"\", \"\") // TODO: maybe add hook retro-compatibility\n content.push(\"[insert_script]\", js_script, \"\");\n\n let over = readOptionalFile(config.over);\n if (over && mode === BuildMode.PRODUCTION) {\n over = JSON.stringify(JSON.parse(over));\n }\n content.push(\"[insert_over]\", over && over != \"{}\" ? over : \"\", \"\");\n return content.join(\"\\n\");\n}\n\nfunction generatePreview(options: ResolvedBuildOptions): string {\n const { config, rootDir } = options;\n\n const external = readOptionalFile(config.external);\n const js_script = fs.readFileSync(path.join(rootDir, config.out.dir, config.out.js), \"utf-8\");\n return fs\n .readFileSync(path.join(SAMMI_NEXT_PACKAGE_DIR, \".sammi\", \"preview.blueprint.html\"), \"utf-8\")\n .replace(/{{EXTERNAL}}/g, external ? `<div id=\"${config.id}-external\">${external}</div>` : \"\")\n .replace(/{{SCRIPT}}/g, js_script);\n}\n\nexport function mergeBuilderOptions(options: BuildOptions) {\n const { config, rootDir, mode } = options;\n\n const default_build_config: TsdownConfig = {\n entry: [config.entry],\n outDir: path.join(rootDir, config.out.dir),\n platform: 'browser',\n format: 'iife',\n target: ['es2022'],\n sourcemap: false,\n minify: mode === BuildMode.PRODUCTION,\n banner: {\n js: `/* ${config.name} v${config.version} - Built with SAMMI Next v${VERSION} */`,\n },\n noExternal: ['**'],\n outputOptions: {\n entryFileNames: config.out.js,\n extend: true,\n name: `${GLOBAL_NAME}.${config.id}`,\n exports: 'named',\n },\n // plugins: [\n // nodePolyfills(),\n // ],\n };\n return lodash.merge(default_build_config, options.config.tsdownConfig);\n}\n\nasync function buildOnce(options: ResolvedBuildOptions) {\n const { config, rootDir } = options;\n\n const startTime = Date.now();\n const bundle = await build(options.config.tsdownConfig);\n const tsdownTime = Date.now();\n console.info(GREEN_CHECK, BUILD_PREFIX, `built ${config.out.js} in ${displayTime(tsdownTime - startTime)}`);\n\n fs.writeFileSync(path.join(rootDir, config.out.dir, config.out.sef), generateSEF(options), 'utf-8');\n const sefTime = Date.now();\n console.info(GREEN_CHECK, BUILD_PREFIX, `built ${config.out.sef} in ${displayTime(sefTime - tsdownTime)}`);\n\n fs.writeFileSync(path.join(rootDir, config.out.dir, \"preview.html\"), generatePreview(options), 'utf-8');\n const previewTime = Date.now();\n console.info(GREEN_CHECK, BUILD_PREFIX, `built preview.html in ${displayTime(previewTime - sefTime)}`);\n return { bundle, startTime };\n}\n\nexport async function buildExtension(options: ResolvedBuildOptions) {\n const { config, mode } = options;\n\n console.info(\n colors.cyan(\n `SAMMI Next v${VERSION} ${colors.green(\n `building \"${config.name}\" extension in ${BuildMode[mode].toLowerCase()} mode...`\n )}`\n ),\n );\n\n let bundle: TsdownBundle[] | undefined;\n let startTime: number | undefined;\n\n try {\n const res = await buildOnce(options);\n bundle = res.bundle;\n startTime = res.startTime;\n\n if (options.mode !== BuildMode.DEV) return bundle;\n\n console.info(BUILD_PREFIX, colors.cyan(\"watching for file changes...\"));\n\n const watchPaths = [\n path.dirname(config.entry),\n config.external,\n config.over,\n ].filter(Boolean);\n\n const watcher = chokidar.watch(watchPaths, { ignoreInitial: true });\n let timer: NodeJS.Timeout | null = null;\n\n watcher.on('all', (event, p) => {\n console.info(colors.cyan(`${event}: ${p}`));\n if (timer)\n clearTimeout(timer);\n\n timer = setTimeout(() => {\n buildOnce(options).then(res => {\n bundle = res.bundle;\n startTime = res.startTime;\n }).catch(e => console.error(e));\n }, 100);\n });\n\n process.on('SIGINT', () => {\n console.info(\"\\nStopping watch mode...\");\n watcher\n .close()\n .then(() => process.exit(0))\n .catch(e => {\n console.error(e);\n process.exit(1);\n });\n });\n return watcher;\n } catch (error) {\n if (startTime) {\n console.error(RED_X, BUILD_PREFIX, `Build failed in ${displayTime(Date.now() - startTime)}`);\n startTime = undefined;\n }\n throw error;\n }\n}\n","\n\nimport { ExtensionConfig, ResolvedExtensionConfig } from \"@shared/config-types\";\nimport Ajv, { JSONSchemaType } from \"ajv\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { DEFAULT_CONFIG_EXTENSIONS } from \"./constants\";\nimport { BuildCLIOptions } from \"./cli\";\nimport { BuildModes, mergeBuilderOptions, ResolvedBuildOptions } from \"./build\";\n\nconst ajv = new Ajv();\n\najv.addKeyword({\n keyword: \"fileExists\",\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n validate: (_schema: any, data: any) => {\n if (!data) return true;\n\n return fs.existsSync(data as string);\n },\n errors: false\n});\n\nconst schema: JSONSchemaType<ExtensionConfig> = {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n minLength: 1,\n pattern: \"^[a-zA-Z0-9-_]+$\",\n },\n name: {\n type: \"string\",\n minLength: 1,\n pattern: \"^[a-zA-Z0-9 -_]+$\",\n },\n info: {\n type: \"string\",\n default: \"\",\n nullable: true,\n },\n version: {\n type: \"string\",\n minLength: 1,\n pattern: \"^\\\\d+(?:\\\\.\\\\d+)*(?:-.*)?$\",\n },\n entry: {\n type: \"string\",\n minLength: 1,\n fileExists: true,\n },\n external: {\n type: \"string\",\n minLength: 1,\n fileExists: true,\n nullable: true,\n },\n over: {\n type: \"string\",\n minLength: 1,\n fileExists: true,\n nullable: true,\n },\n out: {\n type: \"object\",\n properties: {\n dir: {\n type: \"string\",\n minLength: 1,\n pattern: \"^[^<>:\\\"|?*]+$\",\n default: \"dist\",\n nullable: true,\n },\n js: {\n type: \"string\",\n minLength: 4,\n pattern: \"^[\\\\w\\\\-. ]+\\\\.js$\",\n default: \"extension.js\",\n nullable: true,\n },\n sef: {\n type: \"string\",\n minLength: 5,\n pattern: \"^[\\\\w\\\\-. ]+\\\\.sef$\",\n default: \"extension.sef\",\n nullable: true,\n }\n },\n required: [],\n nullable: true,\n additionalProperties: false,\n },\n tsdownConfig: {\n type: \"object\",\n required: [],\n nullable: true,\n additionalProperties: true,\n },\n },\n required: [\"name\", \"id\", \"version\", \"entry\"],\n additionalProperties: true,\n};\n\nconst configValidator = ajv.compile(schema);\n\nexport async function loadConfig(rootDir: string) {\n for (const ext of DEFAULT_CONFIG_EXTENSIONS) {\n const configPath = path.join(rootDir, `sammi.config${ext}`);\n\n if (!fs.existsSync(configPath)) continue;\n\n try {\n const { createJiti } = await import('jiti');\n const jiti = createJiti(rootDir, {\n interopDefault: true,\n moduleCache: true,\n });\n\n const config = await jiti.import(configPath, { default: true });\n\n return validateExtensionConfig(config, configPath);\n } catch (error) {\n throw new Error(`Error loading ${configPath}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n const jsonPath = path.join(rootDir, 'sammi.config.json');\n if (fs.existsSync(jsonPath)) {\n try {\n const raw = fs.readFileSync(jsonPath, 'utf-8');\n const config = JSON.parse(raw) as unknown;\n return validateExtensionConfig(config, jsonPath);\n } catch (error) {\n throw new Error(`Error loading ${jsonPath}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n throw new Error('SAMMI Next extension config file not found in the root dir.');\n}\n\n\nfunction validateExtensionConfig(config: unknown, configPath: string): ExtensionConfig {\n if (!configValidator(config)) {\n const errors = configValidator.errors?.map(err => ` - ${err.instancePath} ${err.message}`).join('\\n');\n throw new Error(`Invalid config from ${configPath}:\\n${errors}`);\n }\n\n return config;\n}\n\nexport function resolveExtensionConfig(config: ExtensionConfig, rootDir: string): ResolvedExtensionConfig {\n const resolved: ResolvedExtensionConfig = {\n id: config.id,\n name: config.name,\n version: config.version,\n info: config.info || '',\n entry: path.resolve(rootDir, config.entry),\n external: config.external ? path.resolve(rootDir, config.external) : '',\n over: config.over ? path.resolve(rootDir, config.over) : '',\n out: {\n dir: config.out?.dir || 'dist',\n js: config.out?.js || 'extension.js',\n sef: config.out?.sef || 'extension.sef',\n },\n tsdownConfig: config.tsdownConfig || {},\n };\n\n if (!fs.existsSync(resolved.entry))\n throw new Error(`Entry file not found: ${resolved.entry}`);\n\n if (resolved.external && !fs.existsSync(resolved.external))\n throw new Error(`External file not found: ${resolved.external}`);\n\n if (resolved.over && !fs.existsSync(resolved.over))\n throw new Error(`Over file not found: ${resolved.over}`);\n\n return resolved;\n}\n\nexport async function resolveBuildConfig(\n root: string | undefined,\n command: string,\n build_cli: BuildCLIOptions,\n) {\n const mode = BuildModes.findIndex(m => {\n return m.toLowerCase() === command.toLowerCase();\n });\n if (mode < 0)\n throw new Error(`Invalid mode: ${command}. It must be one of: ${BuildModes.join(', ')}`);\n\n const rootDir = root ?? process.cwd();\n const config = await loadConfig(rootDir);\n\n config.out ??= {};\n\n config.out.dir = build_cli.outDir ?? config.out.dir;\n config.out.js = build_cli.outJs ?? config.out.js;\n config.out.sef = build_cli.outSef ?? config.out.sef;\n\n const resolvedConfig = resolveExtensionConfig(config, rootDir);\n\n const resolved: ResolvedBuildOptions = {\n rootDir,\n mode,\n config: resolvedConfig\n }\n\n resolved.config.tsdownConfig = mergeBuilderOptions(resolved);\n return resolved;\n}\n","import cac from \"cac\";\r\nimport { buildExtension, BuildMode } from \"./build\";\r\nimport colors from 'picocolors';\r\nimport { resolveBuildConfig } from \"./config\";\r\nimport { VERSION } from \"./constants\";\r\n\r\nconst cli = cac('sammi-next');\r\n\r\nexport interface GlobalCLIOptions {\r\n m?: string\r\n mode?: string\r\n}\r\n\r\nconst filterDuplicateOptions = <T extends object>(options: T) => {\r\n for (const [key, value] of Object.entries(options)) {\r\n if (!Array.isArray(value)) continue;\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\r\n options[key as keyof T] = value[value.length - 1];\r\n }\r\n};\r\n\r\nfunction cleanGlobalCLIOptions<Options extends GlobalCLIOptions>(options: Options): Omit<Options, keyof GlobalCLIOptions> {\r\n const ret = { ...options };\r\n delete ret.m\r\n delete ret.mode\r\n\r\n return ret;\r\n}\r\n\r\ncli.option('-m, --mode <mode>', '[string] set build mode');\r\n\r\nexport interface BuildCLIOptions {\r\n outDir?: string\r\n outJs?: string\r\n outSef?: string\r\n}\r\n\r\ncli\r\n .command('[root]', 'build extension')\r\n .option('--outDir <dir>', '[string] output directory (default: \"dist\")')\r\n .option('--outJs <name>', '[string] output file name for the JS (default: extension.js)')\r\n .option('--outSef <name>', '[string] output file name for the SEF (default: extension.sef)')\r\n .action(\r\n async (\r\n root: string | undefined,\r\n options: GlobalCLIOptions,\r\n ) => {\r\n filterDuplicateOptions(options);\r\n\r\n const buildOptions: BuildCLIOptions = cleanGlobalCLIOptions(options);\r\n\r\n try {\r\n const buildConfig = await resolveBuildConfig(\r\n root,\r\n options.mode || BuildMode[BuildMode.PRODUCTION],\r\n buildOptions,\r\n );\r\n\r\n await buildExtension(buildConfig);\r\n } catch (e) {\r\n const error = e as Error;\r\n console.error(colors.red(`error during build:\\n${error.stack}`));\r\n process.exit(1);\r\n }\r\n }\r\n )\r\n\r\ncli\r\n .command('dev [root]', 'build extension in dev mode')\r\n .option('--outDir <dir>', '[string] output directory (default: \"dist\")')\r\n .option('--outJs <name>', '[string] output file name for the JS (default: extension.js)')\r\n .option('--outSef <name>', '[string] output file name for the SEF (default: extension.sef)')\r\n .action(\r\n async (\r\n root: string | undefined,\r\n options: GlobalCLIOptions,\r\n ) => {\r\n filterDuplicateOptions(options);\r\n\r\n const buildOptions: BuildCLIOptions = cleanGlobalCLIOptions(options);\r\n\r\n try {\r\n const buildConfig = await resolveBuildConfig(\r\n root,\r\n options.mode || BuildMode[BuildMode.DEV],\r\n buildOptions,\r\n );\r\n\r\n await buildExtension(buildConfig);\r\n } catch (e) {\r\n const error = e as Error;\r\n console.error(colors.red(`error during build:\\n${error.stack}`));\r\n process.exit(1);\r\n }\r\n }\r\n )\r\n\r\ncli.help();\r\ncli.version(VERSION);\r\n\r\ncli.parse();\r\n"],"mappings":"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"}
@@ -1,3 +1,5 @@
1
+ import { InlineConfig } from "tsdown";
2
+
1
3
  //#region src/shared/config-types.d.ts
2
4
  /**
3
5
  * Represents the full extension config from sammi.config.ts.
@@ -74,6 +76,14 @@ interface ExtensionConfig {
74
76
  */
75
77
  sef?: string;
76
78
  };
79
+ /**
80
+ * Overrides the tsdown building config.
81
+ *
82
+ * **Use with caution; ensure you understand the implications.**
83
+ *
84
+ * @default undefined
85
+ */
86
+ tsdownConfig?: InlineConfig;
77
87
  }
78
88
  /**
79
89
  * Helper function to define a SAMMI Next extension config with type safety.
@@ -95,6 +105,7 @@ declare function defineConfig(config: ExtensionConfig): ExtensionConfig;
95
105
  /**
96
106
  * Resolved extension config with defaults applied.
97
107
  * Used internally by the builder.
108
+ *
98
109
  * @internal
99
110
  */
100
111
  interface ResolvedExtensionConfig extends Required<Omit<ExtensionConfig, 'out'>> {
@@ -1 +1 @@
1
- {"version":3,"file":"config-types.d.ts","names":[],"sources":["../../src/shared/config-types.ts"],"mappings":";;AAKA;;;UAAiB,eAAA;EAKb;;;;EAAA,EAAA;EAyCA;;;;EAnCA,IAAA;EAmEI;;;AAoBR;;;;EA9EI,IAAA;EA8EyB;;;;AAS7B;;;;;EA5EI,OAAA;EA6Ec;;;;EAvEd,KAAA;EAsE6C;;;;;;;EA7D7C,QAAA;EA8DyC;;;;;;;EArDzC,IAAA;;EAGA,GAAA;;;;;;IAMI,GAAA;;;;;;IAOA,EAAA;;;;;;IAOA,GAAA;EAAA;AAAA;;;;;;;;;;;;;;;;;iBAoBQ,YAAA,CAAa,MAAA,EAAQ,eAAA,GAAkB,eAAA;;;;;;UAStC,uBAAA,SAAgC,QAAA,CAAS,IAAA,CAAK,eAAA;EAC3D,GAAA,EAAK,QAAA,CAAS,WAAA,CAAY,eAAA;AAAA"}
1
+ {"version":3,"file":"config-types.d.ts","names":[],"sources":["../../src/shared/config-types.ts"],"mappings":";;;;;AAMA;;UAAiB,eAAA;EAwFc;;;;EAnF3B,EAAA;EAgCA;;;;EA1BA,IAAA;EA4DI;;;;;;AAoCR;EAvFI,IAAA;;;;;;;;AAiGJ;;EAtFI,OAAA;EAsF2D;;;;EAhF3D,KAAA;EAgF6C;;;;;;;EAvE7C,QAAA;EAwEc;;;;;;;EA/Dd,IAAA;;EAGA,GAAA;;;;;;IAMI,GAAA;;;;;;IAOA,EAAA;;;;;;IAOA,GAAA;EAAA;;;;;;;;EAUJ,YAAA,GAAe,YAAA;AAAA;;;;;;;;;;;;;;;;;iBAmBH,YAAA,CAAa,MAAA,EAAQ,eAAA,GAAkB,eAAA;;;;;;;UAUtC,uBAAA,SAAgC,QAAA,CAAS,IAAA,CAAK,eAAA;EAC3D,GAAA,EAAK,QAAA,CAAS,WAAA,CAAY,eAAA;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"config-types.js","names":[],"sources":["../../src/shared/config-types.ts"],"sourcesContent":["\r\n/**\r\n * Represents the full extension config from sammi.config.ts.\r\n * Used by the CLI to build the extension.\r\n*/\r\nexport interface ExtensionConfig {\r\n /**\r\n * Specify a unique id for your extension here.\r\n * Please use alphanumeric characters, dashes, and underscores only.\r\n */\r\n id: string;\r\n\r\n /**\r\n * This section names your extension, and is visible in SAMMI Bridge and SAMMI Core.\r\n * Please use alphanumeric characters and spaces only.\r\n */\r\n name: string;\r\n\r\n /**\r\n * This section is for descriptive text about the extension, e.g. what the extension does.\r\n * This information is displayed to the users in SAMMI Bridge-Extensions tab when they hover\r\n * over the extension name inside the list of installed extensions.\r\n *\r\n * @default \"\"\r\n */\r\n info?: string;\r\n\r\n /**\r\n * Specify your extension version here, using numbers and dots (e.g., 2.01).\r\n * This is crucial for the automatic version checker in Bridge, which can notify users of updates.\r\n *\r\n * Note: the regex pattern used for validation is `^\\d+(?:\\.\\d+)*(?:-.*)?$`.\r\n * Although SAMMI Next allows beta/alpha suffixes due to its RegExp,\r\n * please note that the official SAMMI Bridge automatic version checker ignores them.\r\n * In other words, the users only will be notified of release updates.\r\n */\r\n version: string;\r\n\r\n /**\r\n * Specify your script.ts path here.\r\n * In your [insert_script] section, you’re encouraged to write your own TypeScript code.\r\n */\r\n entry: string;\r\n\r\n /**\r\n * Specify your external.html path here.\r\n * Your [insert_external] section appears inside the extension’s tab in Bridge,\r\n * and it provides a visual interface for the extension if needed. It’s written in HTML and CSS.\r\n *\r\n * @default undefined\r\n */\r\n external?: string;\r\n\r\n /**\r\n * Specify your over.json path here.\r\n * In your [insert_over] section you simply copy and paste your deck from SAMMI Core you wish to distribute with your extension.\r\n * When users install your extension, the deck will be automatically added to their SAMMI Core.\r\n *\r\n * @default undefined\r\n */\r\n over?: string;\r\n\r\n /** Configuration related with the extension building. */\r\n out?: {\r\n /**\r\n * The path where the extension will build to.\r\n *\r\n * @default \"dist\"\r\n */\r\n dir?: string;\r\n\r\n /**\r\n * The file name of the final JavaScript file.\r\n *\r\n * @default \"extension.js\"\r\n */\r\n js?: string;\r\n\r\n /**\r\n * The file name of the final SAMMI Extension File.\r\n *\r\n * @default \"extension.sef\"\r\n */\r\n sef?: string;\r\n }\r\n}\r\n\r\n/**\r\n * Helper function to define a SAMMI Next extension config with type safety.\r\n *\r\n * @example\r\n * ```ts\r\n * // sammi.config.ts\r\n * import { defineConfig } from 'sammi-next/config';\r\n *\r\n * export default defineConfig({\r\n * id: 'my-extension',\r\n * name: 'My Extension',\r\n * version: '1.0.0',\r\n * entry: 'src/script.ts',\r\n * });\r\n * ```\r\n */\r\nexport function defineConfig(config: ExtensionConfig): ExtensionConfig {\r\n return config;\r\n}\r\n\r\n/**\r\n * Resolved extension config with defaults applied.\r\n * Used internally by the builder.\r\n * @internal\r\n */\r\nexport interface ResolvedExtensionConfig extends Required<Omit<ExtensionConfig, 'out'>> {\r\n out: Required<NonNullable<ExtensionConfig['out']>>;\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;AAuGA,SAAgB,aAAa,QAA0C;AACnE,QAAO"}
1
+ {"version":3,"file":"config-types.js","names":[],"sources":["../../src/shared/config-types.ts"],"sourcesContent":["import type { InlineConfig as TsdownConfig } from \"tsdown\";\n\n/**\n * Represents the full extension config from sammi.config.ts.\n * Used by the CLI to build the extension.\n*/\nexport interface ExtensionConfig {\n /**\n * Specify a unique id for your extension here.\n * Please use alphanumeric characters, dashes, and underscores only.\n */\n id: string;\n\n /**\n * This section names your extension, and is visible in SAMMI Bridge and SAMMI Core.\n * Please use alphanumeric characters and spaces only.\n */\n name: string;\n\n /**\n * This section is for descriptive text about the extension, e.g. what the extension does.\n * This information is displayed to the users in SAMMI Bridge-Extensions tab when they hover\n * over the extension name inside the list of installed extensions.\n *\n * @default \"\"\n */\n info?: string;\n\n /**\n * Specify your extension version here, using numbers and dots (e.g., 2.01).\n * This is crucial for the automatic version checker in Bridge, which can notify users of updates.\n *\n * Note: the regex pattern used for validation is `^\\d+(?:\\.\\d+)*(?:-.*)?$`.\n * Although SAMMI Next allows beta/alpha suffixes due to its RegExp,\n * please note that the official SAMMI Bridge automatic version checker ignores them.\n * In other words, the users only will be notified of release updates.\n */\n version: string;\n\n /**\n * Specify your script.ts path here.\n * In your [insert_script] section, you’re encouraged to write your own TypeScript code.\n */\n entry: string;\n\n /**\n * Specify your external.html path here.\n * Your [insert_external] section appears inside the extension’s tab in Bridge,\n * and it provides a visual interface for the extension if needed. It’s written in HTML and CSS.\n *\n * @default undefined\n */\n external?: string;\n\n /**\n * Specify your over.json path here.\n * In your [insert_over] section you simply copy and paste your deck from SAMMI Core you wish to distribute with your extension.\n * When users install your extension, the deck will be automatically added to their SAMMI Core.\n *\n * @default undefined\n */\n over?: string;\n\n /** Configuration related with the extension building. */\n out?: {\n /**\n * The path where the extension will build to.\n *\n * @default \"dist\"\n */\n dir?: string;\n\n /**\n * The file name of the final JavaScript file.\n *\n * @default \"extension.js\"\n */\n js?: string;\n\n /**\n * The file name of the final SAMMI Extension File.\n *\n * @default \"extension.sef\"\n */\n sef?: string;\n },\n\n /**\n * Overrides the tsdown building config.\n *\n * **Use with caution; ensure you understand the implications.**\n *\n * @default undefined\n */\n tsdownConfig?: TsdownConfig,\n}\n\n/**\n * Helper function to define a SAMMI Next extension config with type safety.\n *\n * @example\n * ```ts\n * // sammi.config.ts\n * import { defineConfig } from 'sammi-next/config';\n *\n * export default defineConfig({\n * id: 'my-extension',\n * name: 'My Extension',\n * version: '1.0.0',\n * entry: 'src/script.ts',\n * });\n * ```\n */\nexport function defineConfig(config: ExtensionConfig): ExtensionConfig {\n return config;\n}\n\n/**\n * Resolved extension config with defaults applied.\n * Used internally by the builder.\n * \n * @internal\n */\nexport interface ResolvedExtensionConfig extends Required<Omit<ExtensionConfig, 'out'>> {\n out: Required<NonNullable<ExtensionConfig['out']>>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiHA,SAAgB,aAAa,QAA0C;AACnE,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sammi-next",
3
- "version": "1.5.2",
3
+ "version": "1.5.3",
4
4
  "author": {
5
5
  "name": "Benjas333",
6
6
  "url": "https://github.com/Benjas333"
@@ -21,6 +21,7 @@
21
21
  "cac": "^6.7.14",
22
22
  "chokidar": "^5.0.0",
23
23
  "jiti": "^2.6.1",
24
+ "lodash": "^4.17.23",
24
25
  "picocolors": "^1.1.1",
25
26
  "tsdown": "^0.20.0-beta.4"
26
27
  },
@@ -65,6 +66,7 @@
65
66
  "types": "./dist/runtime/index.d.ts",
66
67
  "devDependencies": {
67
68
  "@rolldown/plugin-node-polyfills": "^1.0.0",
69
+ "@types/lodash": "^4.17.23",
68
70
  "@types/node": "^25.0.9",
69
71
  "sammi-bridge-types": "sammi-bridge-types"
70
72
  }