@reliverse/dler 1.7.44 → 1.7.46

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.
@@ -24,7 +24,8 @@ export async function dlerBuild(isDev, config, debugOnlyCopyNonBuildFiles, debug
24
24
  effectiveConfig.distNpmDirName,
25
25
  effectiveConfig.distJsrDirName,
26
26
  effectiveConfig.libsDirDist,
27
- effectiveConfig.libsList
27
+ effectiveConfig.libsList,
28
+ "dist-tmp"
28
29
  );
29
30
  if (debugOnlyCopyNonBuildFiles) {
30
31
  if (debugDontCopyNonBuildFiles) {
@@ -5,7 +5,7 @@ import { runCmd } from "@reliverse/rempts";
5
5
  import { glob } from "tinyglobby";
6
6
  import { getCheckCmd } from "../cmds.js";
7
7
  import { getConfigDler } from "../../libs/sdk/sdk-impl/config/load.js";
8
- import { applyMagicSpells } from "../../libs/sdk/sdk-impl/magic/ms-apply.js";
8
+ import { applyMagicSpells } from "../../libs/sdk/sdk-impl/magic/magic-apply.js";
9
9
  import { resolveAllCrossLibs } from "../../libs/sdk/sdk-impl/utils/resolve-cross-libs.js";
10
10
  import { PROJECT_ROOT } from "../../libs/sdk/sdk-impl/utils/utils-consts.js";
11
11
  import { directoryExists, executeDlerHooks } from "./ppb-utils.js";
@@ -35,7 +35,8 @@ export async function dlerPostBuild(isDev, debugDontCopyNonBuildFiles) {
35
35
  }
36
36
  }
37
37
  const distJsrPath = path.join(PROJECT_ROOT, config.distJsrDirName);
38
- if (await directoryExists(distJsrPath)) {
38
+ const distJsrBinPath = path.join(distJsrPath, "bin");
39
+ if (await directoryExists(distJsrPath) && await directoryExists(distJsrBinPath)) {
39
40
  await compareFileStructures(path.join(PROJECT_ROOT, config.coreEntrySrcDir), distJsrPath);
40
41
  }
41
42
  }
@@ -1,5 +1,5 @@
1
1
  import { defineArgs, defineCommand } from "@reliverse/rempts";
2
- import { applyMagicSpells } from "../../libs/sdk/sdk-impl/magic/ms-apply.js";
2
+ import { applyMagicSpells } from "../../libs/sdk/sdk-impl/magic/magic-apply.js";
3
3
  import { formatError } from "../../libs/sdk/sdk-impl/utils/utils-error-cwd.js";
4
4
  export default defineCommand({
5
5
  meta: {
@@ -105,30 +105,29 @@ export default defineCommand({
105
105
  try {
106
106
  await fs.access(path.join(outDir, typesFile));
107
107
  } catch {
108
- const typesContent = `export type FileContent = string | Record<string, unknown>;
109
- export type FileType = "text" | "json" | "binary";
110
- export type FileMetadata = {
108
+ const typesContent = `export interface FileContent extends string | Record<string, unknown> {}
109
+ export interface FileMetadata {
111
110
  updatedAt?: string;
112
111
  updatedHash?: string;
113
- };
114
- export type TemplatesFileContent = {
112
+ }
113
+ export interface TemplatesFileContent {
115
114
  content: FileContent;
116
- type: FileType;
115
+ type: "text" | "json" | "binary";
117
116
  hasError?: boolean;
118
117
  jsonComments?: Record<number, string>;
119
118
  binaryHash?: string;
120
119
  metadata?: FileMetadata;
121
- };
122
- export type TemplateConfig = {
120
+ }
121
+ export interface TemplateConfig {
123
122
  files: Record<string, TemplatesFileContent>;
124
- };
125
- export type Template = {
123
+ }
124
+ export interface Template {
126
125
  name: string;
127
126
  description: string;
128
127
  config: TemplateConfig;
129
128
  updatedAt?: string;
130
- };
131
- export type Templates = Record<string, Template>;
129
+ }
130
+ export interface Templates extends Record<string, Template> {}
132
131
  `;
133
132
  await fs.writeFile(path.join(outDir, typesFile), typesContent);
134
133
  }
@@ -250,7 +249,7 @@ export type Templates = Record<string, Template>;
250
249
  ).split("\n").map((line, i) => {
251
250
  if (i === 0) return line;
252
251
  return " " + line.replace(/"([a-zA-Z0-9_]+)":/g, "$1:");
253
- }).join("\n").replace(/}$/m, "},");
252
+ }).join("\n").replace(/},?\s*$/, "},");
254
253
  code.push(` content: ${jsonStr}${sat},`);
255
254
  code.push(' type: "json",');
256
255
  }
@@ -297,7 +296,7 @@ export type Templates = Record<string, Template>;
297
296
  "",
298
297
  `export const ${WL}_TEMPLATES = ${WL}_TEMPLATES_OBJ as const;`,
299
298
  "",
300
- `export type ${WL}_TEMPLATE_NAMES = keyof typeof ${WL}_TEMPLATES;`,
299
+ `export interface ${WL}_TEMPLATE_NAMES extends keyof typeof ${WL}_TEMPLATES {}`,
301
300
  "",
302
301
  `export const dlerTemplatesMap: Record<string, ${WL}_TEMPLATE_NAMES> = {`,
303
302
  ...mapEntries,
@@ -10,8 +10,8 @@ export declare const defineConfigRse: (userConfig?: Partial<RseConfig>) => {
10
10
  projectDomain?: string | undefined;
11
11
  projectGitService?: "none" | "github" | "gitlab" | "bitbucket" | undefined;
12
12
  projectDeployService?: "none" | "vercel" | "netlify" | "railway" | "deno" | undefined;
13
- projectPackageManager?: "npm" | "bun" | "pnpm" | "yarn" | undefined;
14
- projectState?: "created" | "creating" | undefined;
13
+ projectPackageManager?: "npm" | "bun" | "yarn" | "pnpm" | undefined;
14
+ projectState?: "creating" | "created" | undefined;
15
15
  projectCategory?: "browser" | "cli" | "unknown" | "website" | "vscode" | "library" | "mobile" | undefined;
16
16
  projectSubcategory?: "unknown" | "e-commerce" | "tool" | undefined;
17
17
  projectFramework?: "rempts" | "npm-jsr" | "unknown" | "vscode" | "nextjs" | "vite" | "svelte" | "remix" | "astro" | "nuxt" | "solid" | "qwik" | "vue" | "wxt" | "lynx" | "react-native" | "expo" | "capacitor" | "ionic" | "electron" | "tauri" | "neutralino" | "citty" | "commander" | "cac" | "meow" | "yargs" | "webextension" | "browser-extension" | undefined;
@@ -34,10 +34,11 @@ export declare const defineConfigRse: (userConfig?: Partial<RseConfig>) => {
34
34
  } | undefined;
35
35
  preferredLibraries?: {
36
36
  search?: "unknown" | "algolia" | undefined;
37
+ cdn?: "unknown" | "cloudflare" | undefined;
37
38
  i18n?: "unknown" | "next-intl" | undefined;
38
39
  analytics?: "unknown" | "vercel" | undefined;
39
40
  authentication?: "unknown" | "better-auth" | "clerk" | "next-auth" | "supabase-auth" | "auth0" | undefined;
40
- api?: "unknown" | "hono" | "trpc" | "graphql" | "rest" | undefined;
41
+ api?: "rest" | "unknown" | "hono" | "trpc" | "graphql" | undefined;
41
42
  testing?: "bun" | "unknown" | "vitest" | "jest" | "playwright" | "cypress" | undefined;
42
43
  stateManagement?: "unknown" | "zustand" | "jotai" | "redux-toolkit" | undefined;
43
44
  formManagement?: "unknown" | "react-hook-form" | "formik" | undefined;
@@ -59,7 +60,6 @@ export declare const defineConfigRse: (userConfig?: Partial<RseConfig>) => {
59
60
  mail?: "unknown" | "resend" | undefined;
60
61
  cache?: "unknown" | "redis" | undefined;
61
62
  storage?: "unknown" | "cloudflare" | undefined;
62
- cdn?: "unknown" | "cloudflare" | undefined;
63
63
  cms?: "unknown" | "contentlayer" | undefined;
64
64
  seo?: "unknown" | "next-seo" | undefined;
65
65
  motion?: "unknown" | "framer" | undefined;
@@ -75,7 +75,7 @@ export declare const defineConfigRse: (userConfig?: Partial<RseConfig>) => {
75
75
  indentStyle?: "space" | "tab" | undefined;
76
76
  quoteMark?: "single" | "double" | undefined;
77
77
  semicolons?: boolean | undefined;
78
- trailingComma?: "none" | "es5" | "all" | undefined;
78
+ trailingComma?: "none" | "all" | "es5" | undefined;
79
79
  bracketSpacing?: boolean | undefined;
80
80
  arrowParens?: "always" | "avoid" | undefined;
81
81
  tabWidth?: number | undefined;
@@ -96,7 +96,7 @@ export declare const defineConfigRse: (userConfig?: Partial<RseConfig>) => {
96
96
  importSymbol?: string | undefined;
97
97
  } | undefined;
98
98
  monorepo?: {
99
- type?: "none" | "bun" | "turborepo" | "nx" | "pnpm" | undefined;
99
+ type?: "none" | "bun" | "pnpm" | "turborepo" | "nx" | undefined;
100
100
  packages?: string[] | undefined;
101
101
  sharedPackages?: string[] | undefined;
102
102
  } | undefined;
@@ -1,5 +1,5 @@
1
1
  import { endPrompt, startPrompt } from "@reliverse/rempts";
2
- const version = "1.7.44";
2
+ const version = "1.7.46";
3
3
  export async function showStartPrompt(isDev) {
4
4
  await startPrompt({
5
5
  titleColor: "inverse",
@@ -25,6 +25,8 @@ export interface ApplyMagicSpellsOptions {
25
25
  export interface ApplyMagicSpellsResult {
26
26
  /** All processed files */
27
27
  processedFiles: string[];
28
+ /** Total number of magic spells processed */
29
+ totalSpellsProcessed: number;
28
30
  }
29
31
  /**
30
32
  * Processes files in specified output directories by applying magic directives
@@ -6,7 +6,7 @@ import { isBinaryExt } from "../utils/binary.js";
6
6
  import { formatError } from "../utils/utils-error-cwd.js";
7
7
  import {
8
8
  evaluateMagicDirective
9
- } from "./ms-spells.js";
9
+ } from "./magic-spells.js";
10
10
  const DEBUG_MODE = true;
11
11
  const PROCESS_DTS_FILES = true;
12
12
  const DEFAULT_OPTIONS = {
@@ -30,17 +30,17 @@ function validateTargets(targets, customOutputPaths) {
30
30
  if (!outputDir) {
31
31
  throw new Error(`Invalid output target: ${target}`);
32
32
  }
33
- const outputPath = allOutputPaths[outputDir] || outputDir;
34
- const fullPath = path.isAbsolute(outputPath) ? outputPath : path.join(process.cwd(), outputPath);
35
- if (!fs.existsSync(fullPath)) {
36
- throw new Error(`Output directory does not exist: ${outputPath}`);
37
- }
38
33
  const isCustomTarget = !["dist-npm", "dist-jsr", "dist-libs"].includes(outputDir);
39
34
  if (isCustomTarget) {
40
35
  if (customTargets.has(outputDir)) {
41
36
  throw new Error(`Duplicate custom target: ${outputDir}`);
42
37
  }
43
38
  customTargets.add(outputDir);
39
+ const outputPath = allOutputPaths[outputDir] || outputDir;
40
+ const fullPath = path.isAbsolute(outputPath) ? outputPath : path.join(process.cwd(), outputPath);
41
+ if (!fs.existsSync(fullPath)) {
42
+ throw new Error(`Output directory does not exist: ${outputPath}`);
43
+ }
44
44
  continue;
45
45
  }
46
46
  if (outputDir === "dist-libs") {
@@ -65,7 +65,8 @@ function validateTargets(targets, customOutputPaths) {
65
65
  }
66
66
  export async function applyMagicSpells(targets, options = {}) {
67
67
  const result = {
68
- processedFiles: []
68
+ processedFiles: [],
69
+ totalSpellsProcessed: 0
69
70
  };
70
71
  try {
71
72
  validateTargets(targets, options.customOutputPaths);
@@ -76,6 +77,7 @@ export async function applyMagicSpells(targets, options = {}) {
76
77
  if (outputDir && !["dist-npm", "dist-jsr", "dist-libs"].includes(outputDir)) {
77
78
  const targetResult = await processCustomTarget(outputDir, options);
78
79
  result.processedFiles.push(...targetResult.processedFiles);
80
+ result.totalSpellsProcessed += targetResult.totalSpellsProcessed;
79
81
  return;
80
82
  }
81
83
  const srcRoot = path.resolve(process.cwd(), "src");
@@ -92,25 +94,36 @@ export async function applyMagicSpells(targets, options = {}) {
92
94
  if (outputDir === "dist-libs") {
93
95
  if (!lib) {
94
96
  const distLibsPath = DEFAULT_OUTPUT_PATHS["dist-libs"] ?? "dist-libs";
95
- const libDirs = await readdir(distLibsPath, { withFileTypes: true });
96
- await pMap(
97
- libDirs,
98
- async (libDir) => {
99
- if (libDir.isDirectory()) {
100
- const targetResult = await processOutputTarget(
101
- sourceFilesWithDirectives,
102
- "dist-libs",
103
- libDir.name,
104
- options
105
- );
106
- result.processedFiles.push(...targetResult.processedFiles);
107
- }
108
- },
109
- {
110
- concurrency: options.concurrency ?? 4,
111
- stopOnError: options.stopOnError ?? true
97
+ try {
98
+ if (await fs.pathExists(distLibsPath)) {
99
+ const libDirs = await readdir(distLibsPath, { withFileTypes: true });
100
+ await pMap(
101
+ libDirs,
102
+ async (libDir) => {
103
+ if (libDir.isDirectory()) {
104
+ const targetResult = await processOutputTarget(
105
+ sourceFilesWithDirectives,
106
+ "dist-libs",
107
+ libDir.name,
108
+ options
109
+ );
110
+ result.processedFiles.push(...targetResult.processedFiles);
111
+ result.totalSpellsProcessed += targetResult.totalSpellsProcessed;
112
+ }
113
+ },
114
+ {
115
+ concurrency: options.concurrency ?? 4,
116
+ stopOnError: options.stopOnError ?? true
117
+ }
118
+ );
119
+ } else if (DEBUG_MODE) {
120
+ relinka("log", `[spells] \u2298 skipping non-existent target: ${distLibsPath}`);
112
121
  }
113
- );
122
+ } catch (error) {
123
+ if (DEBUG_MODE) {
124
+ relinka("warn", `Failed to process dist-libs: ${formatError(error)}`);
125
+ }
126
+ }
114
127
  } else {
115
128
  const targetResult = await processOutputTarget(
116
129
  sourceFilesWithDirectives,
@@ -119,6 +132,7 @@ export async function applyMagicSpells(targets, options = {}) {
119
132
  options
120
133
  );
121
134
  result.processedFiles.push(...targetResult.processedFiles);
135
+ result.totalSpellsProcessed += targetResult.totalSpellsProcessed;
122
136
  }
123
137
  } else if (outputDir) {
124
138
  const targetResult = await processOutputTarget(
@@ -128,6 +142,7 @@ export async function applyMagicSpells(targets, options = {}) {
128
142
  options
129
143
  );
130
144
  result.processedFiles.push(...targetResult.processedFiles);
145
+ result.totalSpellsProcessed += targetResult.totalSpellsProcessed;
131
146
  }
132
147
  },
133
148
  {
@@ -135,6 +150,12 @@ export async function applyMagicSpells(targets, options = {}) {
135
150
  stopOnError: options.stopOnError ?? true
136
151
  }
137
152
  );
153
+ if (DEBUG_MODE) {
154
+ relinka(
155
+ "log",
156
+ `[spells] \u2713 Processed ${result.totalSpellsProcessed} magic spells in ${result.processedFiles.length} files`
157
+ );
158
+ }
138
159
  return result;
139
160
  } catch (error) {
140
161
  throw new Error(`Failed to process output files: ${formatError(error)}`);
@@ -143,7 +164,8 @@ export async function applyMagicSpells(targets, options = {}) {
143
164
  async function processCustomTarget(outputDir, options = {}) {
144
165
  const { concurrency = DEFAULT_OPTIONS.concurrency, batchSize = DEFAULT_OPTIONS.batchSize } = options;
145
166
  const result = {
146
- processedFiles: []
167
+ processedFiles: [],
168
+ totalSpellsProcessed: 0
147
169
  };
148
170
  if (DEBUG_MODE) {
149
171
  relinka("log", `[spells] \u21D2 processing custom target: ${outputDir}`);
@@ -191,6 +213,9 @@ async function processCustomTarget(outputDir, options = {}) {
191
213
  const wasProcessed = await processSingleOutputFile(outputFilePath, options);
192
214
  if (wasProcessed) {
193
215
  result.processedFiles.push(outputFilePath);
216
+ const content = await fs.readFile(outputFilePath, "utf8");
217
+ const spellCount = (content.match(/\/\/\s*(?:@ts-expect-error\s+.*?)?<\s*(dler-[^>\s]+)(.*?)>/gi) || []).length;
218
+ result.totalSpellsProcessed += spellCount;
194
219
  }
195
220
  } catch (error) {
196
221
  const errorMessage = `Error processing ${outputFilePath}: ${formatError(error)}`;
@@ -245,8 +270,18 @@ async function scanSourceForMagicDirectives(srcRoot, options = {}) {
245
270
  async function processOutputTarget(sourceFilesWithDirectives, outputDir, libName, options = {}) {
246
271
  const { concurrency = DEFAULT_OPTIONS.concurrency, batchSize = DEFAULT_OPTIONS.batchSize } = options;
247
272
  const result = {
248
- processedFiles: []
273
+ processedFiles: [],
274
+ totalSpellsProcessed: 0
249
275
  };
276
+ const outputPath = options.customOutputPaths?.[outputDir] || outputDir;
277
+ const fullOutputPath = path.isAbsolute(outputPath) ? outputPath : path.join(process.cwd(), outputPath);
278
+ if (!await fs.pathExists(fullOutputPath)) {
279
+ if (DEBUG_MODE) {
280
+ const targetName = outputDir === "dist-libs" && libName ? `${outputDir}/${libName}` : outputDir;
281
+ relinka("log", `[spells] \u2298 skipping non-existent target: ${targetName}`);
282
+ }
283
+ return result;
284
+ }
250
285
  if (DEBUG_MODE) {
251
286
  const targetName = outputDir === "dist-libs" && libName ? `${outputDir}/${libName}` : outputDir;
252
287
  relinka("log", `[spells] \u21D2 processing target: ${targetName}`);
@@ -277,6 +312,9 @@ async function processOutputTarget(sourceFilesWithDirectives, outputDir, libName
277
312
  const wasProcessed = await processSingleOutputFile(outputFilePath, options);
278
313
  if (wasProcessed) {
279
314
  result.processedFiles.push(outputFilePath);
315
+ const content = await fs.readFile(outputFilePath, "utf8");
316
+ const spellCount = (content.match(/\/\/\s*(?:@ts-expect-error\s+.*?)?<\s*(dler-[^>\s]+)(.*?)>/gi) || []).length;
317
+ result.totalSpellsProcessed += spellCount;
280
318
  }
281
319
  } catch (error) {
282
320
  const errorMessage = `Error processing ${outputFilePath}: ${formatError(error)}`;
@@ -2,7 +2,7 @@ import type { LibConfig } from "../config/types.js";
2
2
  /**
3
3
  * Recursively removes any existing distribution folders.
4
4
  */
5
- export declare function removeDistFolders(distNpmDirName: string, distJsrDirName: string, libsDirDist: string, libsList: Record<string, LibConfig>): Promise<boolean>;
5
+ export declare function removeDistFolders(distNpmDirName: string, distJsrDirName: string, libsDirDist: string, libsList: Record<string, LibConfig>, distTmpDirName?: string): Promise<boolean>;
6
6
  /**
7
7
  * Removes logInternal and relinka "internal" calls from TypeScript/JavaScript files
8
8
  * @param targetDir Directory to process recursively
@@ -3,10 +3,13 @@ import fs from "@reliverse/relifso";
3
3
  import { relinka } from "@reliverse/relinka";
4
4
  import pMap from "p-map";
5
5
  import { CONCURRENCY_DEFAULT, PROJECT_ROOT } from "./utils-consts.js";
6
- export async function removeDistFolders(distNpmDirName, distJsrDirName, libsDirDist, libsList) {
6
+ export async function removeDistFolders(distNpmDirName, distJsrDirName, libsDirDist, libsList, distTmpDirName = "") {
7
7
  const foldersToRemove = [];
8
8
  foldersToRemove.push(distNpmDirName);
9
9
  foldersToRemove.push(distJsrDirName);
10
+ if (distTmpDirName !== "") {
11
+ foldersToRemove.push(distTmpDirName);
12
+ }
10
13
  if (libsList && Object.keys(libsList).length > 0) {
11
14
  foldersToRemove.push(libsDirDist);
12
15
  }
@@ -43,10 +43,10 @@ export { getConfigDler } from "./sdk-impl/config/load.js";
43
43
  export type { DlerConfig, BumpMode, BundlerName, NpmOutExt, LibConfig, Esbuild, transpileFormat, Sourcemap, transpileTarget, } from "./sdk-impl/config/types.js";
44
44
  export { IGNORE_PATTERNS } from "./sdk-impl/constants.js";
45
45
  export { library_buildFlow, library_pubFlow, libraries_build, libraries_publish, } from "./sdk-impl/library-flow.js";
46
- export type { ApplyMagicSpellsOptions, ApplyMagicSpellsResult, FileWithSpells, } from "./sdk-impl/magic/ms-apply.js";
47
- export { applyMagicSpells, processSingleOutputFile, getAllAvailableRegistries, getFilesWithMagicSpells, } from "./sdk-impl/magic/ms-apply.js";
48
- export type { SpellEvaluationContext, SpellOutcome, SpellDirective, SpellInfo, } from "./sdk-impl/magic/ms-spells.js";
49
- export { getAvailableSpells, evaluateMagicDirective } from "./sdk-impl/magic/ms-spells.js";
46
+ export type { ApplyMagicSpellsOptions, ApplyMagicSpellsResult, FileWithSpells, } from "./sdk-impl/magic/magic-apply.js";
47
+ export { applyMagicSpells, processSingleOutputFile, getAllAvailableRegistries, getFilesWithMagicSpells, } from "./sdk-impl/magic/magic-apply.js";
48
+ export type { SpellEvaluationContext, SpellOutcome, SpellDirective, SpellInfo, } from "./sdk-impl/magic/magic-spells.js";
49
+ export { getAvailableSpells, evaluateMagicDirective } from "./sdk-impl/magic/magic-spells.js";
50
50
  export { library_publishLibrary } from "./sdk-impl/pub/pub-library.js";
51
51
  export { regular_pubToJsr, regular_pubToNpm } from "./sdk-impl/pub/pub-regular.js";
52
52
  export { regular_buildFlow, regular_pubFlow } from "./sdk-impl/regular-flow.js";
@@ -118,8 +118,8 @@ export {
118
118
  processSingleOutputFile,
119
119
  getAllAvailableRegistries,
120
120
  getFilesWithMagicSpells
121
- } from "./sdk-impl/magic/ms-apply.js";
122
- export { getAvailableSpells, evaluateMagicDirective } from "./sdk-impl/magic/ms-spells.js";
121
+ } from "./sdk-impl/magic/magic-apply.js";
122
+ export { getAvailableSpells, evaluateMagicDirective } from "./sdk-impl/magic/magic-spells.js";
123
123
  export { library_publishLibrary } from "./sdk-impl/pub/pub-library.js";
124
124
  export { regular_pubToJsr, regular_pubToNpm } from "./sdk-impl/pub/pub-regular.js";
125
125
  export { regular_buildFlow, regular_pubFlow } from "./sdk-impl/regular-flow.js";
package/package.json CHANGED
@@ -53,7 +53,7 @@
53
53
  "license": "MIT",
54
54
  "name": "@reliverse/dler",
55
55
  "type": "module",
56
- "version": "1.7.44",
56
+ "version": "1.7.46",
57
57
  "keywords": [
58
58
  "reliverse",
59
59
  "cli",
@@ -1,143 +0,0 @@
1
- import { relinka } from "@reliverse/relinka";
2
- const SPELL_REGEX = /\/\/\s*(?:@ts-expect-error\s+.*?)?<\s*(dler-[^>\s]+)(.*?)>/i;
3
- const REPLACEMENT_REGEX = /`([^`]+)`/;
4
- const IF_CONDITION_REGEX = /\bif\s+['"`]([^'"`]+)['"`]/i;
5
- const ELSE_CONTENT_REGEX = /\belse\s+['"`]([^'"`]+)['"`]/i;
6
- const STARTS_WITH_REGEX = /current file path starts with\s+(.+)$/i;
7
- export function getAvailableSpells() {
8
- return [
9
- {
10
- name: "dler-replace-line-to",
11
- description: "Replaces the current line with new content, optionally based on a condition",
12
- example: "// <dler-replace-line-to `export const version = \"1.0.0\";` if 'current file path starts with dist-npm'>",
13
- notes: "If no condition is specified, replacement always applies. If condition is not met and else content is provided, uses else content. Otherwise keeps original line. Also supports @ts-expect-error prefix."
14
- },
15
- {
16
- name: "dler-remove-line",
17
- description: "Removes the current line from the output",
18
- example: "// <dler-remove-line>",
19
- notes: "Also supports @ts-expect-error prefix."
20
- },
21
- {
22
- name: "dler-remove-file",
23
- description: "Removes the entire file from the output",
24
- example: "// <dler-remove-file>",
25
- notes: "This directive should be placed at the top of the file for clarity. Also supports @ts-expect-error prefix."
26
- },
27
- {
28
- name: "dler-remove-comment",
29
- description: "Removes only the comment portion containing this directive from the line",
30
- example: "console.log('debug info'); // <dler-remove-comment>",
31
- notes: "Removes everything from '//' to the end of the line when the comment contains this directive. The code portion before the comment is preserved. Also supports @ts-expect-error prefix."
32
- },
33
- {
34
- name: "dler-ignore-this-line",
35
- description: "Prevents any magic directives on this line from being processed",
36
- example: "// <dler-remove-line> // <dler-ignore-this-line>",
37
- notes: "When present on a line, all magic directives on that line are ignored and the line is kept as-is. Useful for code that contains magic directive strings that shouldn't be executed."
38
- }
39
- ];
40
- }
41
- export function evaluateMagicDirective(line, ctx) {
42
- if (line.includes("<dler-ignore-this-line>")) {
43
- return NO_OP;
44
- }
45
- const match = line.match(SPELL_REGEX);
46
- if (!match) return NO_OP;
47
- const [, directive = "", body] = match;
48
- if (!isValidMagicDirective(directive)) {
49
- relinka("warn", `[spells] unknown directive: ${directive}`);
50
- return NO_OP;
51
- }
52
- switch (directive) {
53
- /* -------------------------------------------------------------- */
54
- /* dler-remove-file */
55
- /* -------------------------------------------------------------- */
56
- case "dler-remove-file": {
57
- return { removeFile: true, removeLine: true };
58
- }
59
- /* -------------------------------------------------------------- */
60
- /* dler-remove-line */
61
- /* -------------------------------------------------------------- */
62
- case "dler-remove-line": {
63
- return { removeLine: true, removeFile: false };
64
- }
65
- /* -------------------------------------------------------------- */
66
- /* dler-remove-comment */
67
- /* -------------------------------------------------------------- */
68
- case "dler-remove-comment": {
69
- const commentIndex = line.indexOf("//");
70
- if (commentIndex !== -1) {
71
- const codeBeforeComment = line.substring(0, commentIndex).trimEnd();
72
- return { replacement: codeBeforeComment, removeLine: false, removeFile: false };
73
- }
74
- return NO_OP;
75
- }
76
- /* -------------------------------------------------------------- */
77
- /* dler-replace-line-to */
78
- /* -------------------------------------------------------------- */
79
- case "dler-replace-line-to": {
80
- const { replacement, elseContent, condition } = parseReplacementDirective(body ?? "");
81
- if (!replacement) {
82
- relinka("warn", "[spells] dler-replace-line-to missing replacement content");
83
- return NO_OP;
84
- }
85
- const condMet = condition === void 0 ? true : evaluatePathCondition(condition, ctx);
86
- if (condMet) {
87
- return { replacement, removeLine: false, removeFile: false };
88
- }
89
- if (elseContent !== void 0) {
90
- return { replacement: elseContent, removeLine: false, removeFile: false };
91
- }
92
- return NO_OP;
93
- }
94
- /* -------------------------------------------------------------- */
95
- /* dler-ignore-this-line */
96
- /* -------------------------------------------------------------- */
97
- case "dler-ignore-this-line": {
98
- return NO_OP;
99
- }
100
- default:
101
- return NO_OP;
102
- }
103
- }
104
- const NO_OP = { removeLine: false, removeFile: false };
105
- function isValidMagicDirective(directive) {
106
- return [
107
- "dler-replace-line-to",
108
- "dler-remove-line",
109
- "dler-remove-file",
110
- "dler-remove-comment",
111
- "dler-ignore-this-line"
112
- ].includes(directive);
113
- }
114
- function parseReplacementDirective(body) {
115
- const parts = {
116
- replacement: ""
117
- };
118
- const replacementMatch = body.match(REPLACEMENT_REGEX);
119
- if (replacementMatch?.[1]) parts.replacement = replacementMatch[1].trim();
120
- const ifMatch = body.match(IF_CONDITION_REGEX);
121
- if (ifMatch?.[1]) {
122
- parts.condition = ifMatch[1].trim();
123
- }
124
- const elseMatch = body.match(ELSE_CONTENT_REGEX);
125
- if (elseMatch?.[1]) parts.elseContent = elseMatch[1].trim();
126
- return parts;
127
- }
128
- function evaluatePathCondition(condition, ctx) {
129
- const STARTS_WITH = STARTS_WITH_REGEX.exec(condition)?.[1];
130
- if (STARTS_WITH) {
131
- const prefixes = STARTS_WITH.split(/\s+or\s+/i).map(
132
- (p) => p.replace(/['"`]/g, "").trim().replaceAll("\\", "/")
133
- );
134
- return prefixes.some((p) => ctx.filePath.startsWith(p));
135
- }
136
- if (condition.trim()) {
137
- relinka(
138
- "warn",
139
- `[spells] unsupported condition "${condition}" - only "current file path starts with <prefix> [or <prefix> ...]" is supported`
140
- );
141
- }
142
- return false;
143
- }