Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c10f44a
perf(core/eslint-config): update version and sort config entries
stephansama May 8, 2026
c73d5b3
chore(core): update tsconfig to use base and add composite flag
stephansama May 8, 2026
b5d3dec
chore(tsconfig): add tsdown.config.ts to include in multiple projects
stephansama May 9, 2026
fe35a4a
chore(eslint): add virtual:.* to ignore list
stephansama May 9, 2026
f25e306
feat(docs): add eslint rule for import sorting
stephansama May 9, 2026
35c90ea
refactor(iconify): remove .ts extension from import paths
stephansama May 9, 2026
b83cae0
ci(core): update build and dev scripts to use tsx
stephansama May 9, 2026
166c1a6
feat(core): add tsx dependency
stephansama May 9, 2026
4917e8b
feat(core): update package dependencies to use catalog:manypkg and sp…
stephansama May 9, 2026
9624632
perf(vitest): cast plugin to any to bypass type error
stephansama May 9, 2026
85875b4
ci(build): add build script for generating examples
stephansama May 9, 2026
bc36958
feat(build): add setup scripts and linting to www package
stephansama May 9, 2026
0b3632c
feat(core): add presetup:eslint-config-inspector task
stephansama May 9, 2026
d9dd43c
test(ai-commit-msg): fix mock for dotenvx config
stephansama May 9, 2026
679e24a
refactor(core): migrate build process to tsdown config
stephansama May 9, 2026
8c2b6ee
chore(docs): exclude tsdown.config.ts from typedoc
stephansama May 9, 2026
da5b73b
feat(docs): update package.json to include examples in prelint
stephansama May 9, 2026
79a4e38
docs(config): update typedoc config to use package options
stephansama May 9, 2026
6fc918a
feat(config): add typedoc-sidebar script and setup task
stephansama May 9, 2026
a20f96f
chore: update repository config for examples
stephansama May 9, 2026
a1b3b0b
chore(core): add tsbuildinfo to gitignore
stephansama May 9, 2026
70fa850
chore: update dependencies in changeset
stephansama May 9, 2026
8ba1cd9
docs(core): add package logo and alignment
stephansama May 9, 2026
85dc1a2
feat(docs): add line numbers and hide breadcrumbs in vitepress config
stephansama May 9, 2026
3ef2721
chore(config): update prettier config path in nanostaged
stephansama May 9, 2026
c146a44
ci(README): update readme with auto-readme
stephansama May 9, 2026
206a502
ci(config): add lint staged job
stephansama May 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .config/www/.vitepress/theme/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Theme } from "vitepress";
import CopyOrDownloadAsMarkdownButtons from "vitepress-plugin-llms/vitepress-components/CopyOrDownloadAsMarkdownButtons.vue";
import DefaultTheme from "vitepress/theme";

// eslint-disable-next-line
// eslint-disable-next-line perfectionist/sort-imports
import "@catppuccin/vitepress/theme/mocha/red.css";

import "./extend.css";
Expand Down
1 change: 1 addition & 0 deletions .config/www/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"build": "vitepress build",
"predev": "pnpm run setup",
"dev": "vitepress dev",
"lint": "eslint ./",
"lint:fix": "eslint ./ --fix",
"preview": "vitepress preview",
"setup": "sh ./setup.sh"
Expand Down
8 changes: 8 additions & 0 deletions .config/www/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use array format for extends to maintain consistency.

While TypeScript accepts both string and array formats for extends, all other tsconfig.json files in this PR use the array format: "extends": ["../../tsconfig.base.json"]. This inconsistency may cause confusion.

📝 Proposed fix
-  "extends": "../../tsconfig.base.json",
+  "extends": ["../../tsconfig.base.json"],
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"extends": "../../tsconfig.base.json",
"extends": ["../../tsconfig.base.json"],
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.config/www/tsconfig.json at line 2, Update the "extends" entry in
.config/www/tsconfig.json from a string to an array to match the other configs:
change the "extends" property so it uses the array form (i.e., "extends":
["../../tsconfig.base.json"]) to keep consistency with the project's tsconfig
files.

"include": [".vitepress/**/*"],
"compilerOptions": {
"composite": true,
"types": ["node"]
}
}
5 changes: 2 additions & 3 deletions core/ai-commit-msg/build.mjs → core/ai-commit-msg/build.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as fsp from "node:fs/promises";
import path from "node:path";
import { build as tsdown } from "tsdown";
import { build as tsdown, type UserConfig } from "tsdown";
import * as z from "zod";

const outDirectory = path.resolve("./dist");
Expand All @@ -18,8 +18,7 @@ const jsonString = JSON.stringify(jsonSchema);

await fsp.writeFile(path.join(schemaDirectory, "schema.json"), jsonString);

/** @param {import("tsdown").Options} options */
function build(options) {
function build(options: UserConfig) {
return tsdown({
attw: { excludeEntrypoints: ["schema.json"] },
format: ["esm", "cjs"],
Expand Down
14 changes: 7 additions & 7 deletions core/ai-commit-msg/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,16 @@
"lint:fix": "eslint ./src/ --pass-on-no-patterns --no-error-on-unmatched-pattern --fix"
},
"dependencies": {
"@ai-sdk/google": "^3.0.29",
"@ai-sdk/openai": "^3.0.29",
"@commitlint/config-conventional": "^19.8.1",
"@dotenvx/dotenvx": "^1.52.0",
"ai": "^6.0.86",
"@ai-sdk/google": "catalog:ai",
"@ai-sdk/openai": "catalog:ai",
"@commitlint/config-conventional": "catalog:commitlint",
"@dotenvx/dotenvx": "catalog:",
"ai": "catalog:ai",
"cosmiconfig": "catalog:cli",
"es-toolkit": "catalog:",
"neverthrow": "^8.2.0",
"neverthrow": "catalog:",
"obug": "catalog:cli",
"ollama-ai-provider-v2": "^1.5.5",
"ollama-ai-provider-v2": "catalog:ai",
"yargs": "catalog:cli",
"zod": "catalog:schema"
},
Expand Down
1 change: 0 additions & 1 deletion core/ai-commit-msg/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// eslint-disable-next-line e18e/ban-dependencies
import { cosmiconfig, getDefaultSearchPlaces, type Options } from "cosmiconfig";

import { type Config, configSchema } from "./schema";
Expand Down
2 changes: 1 addition & 1 deletion core/ai-commit-msg/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import dotenvx from "@dotenvx/dotenvx";
import * as dotenvx from "@dotenvx/dotenvx";
import { generateText } from "ai";
import * as cp from "node:child_process";
import * as fsp from "node:fs/promises";
Expand Down
4 changes: 4 additions & 0 deletions core/ai-commit-msg/test/ai.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { afterEach, describe, expect, it, vi } from "vitest";

import { getProvider } from "../src/ai";

/* eslint-disable @typescript-eslint/no-unsafe-assignment */

vi.mock("@ai-sdk/google", () => ({
google: vi.fn((model) => ({ model, type: "google" })),
}));
Expand All @@ -17,6 +19,8 @@ vi.mock("ollama-ai-provider-v2", () => ({
ollama: vi.fn((model) => ({ model, type: "ollama" })),
}));

/* eslint-enable @typescript-eslint/no-unsafe-assignment */

describe("ai", () => {
const originalEnvironment = process.env;

Expand Down
2 changes: 2 additions & 0 deletions core/ai-commit-msg/test/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable unicorn/no-abusive-eslint-disable */
/* eslint-disable */
Comment on lines +1 to +2

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check which ESLint rules are violated in config.test.ts

# Remove the eslint-disable comments temporarily and run ESLint
rg -n "eslint-disable" core/ai-commit-msg/test/config.test.ts

Repository: stephansama/packages

Length of output: 144


🏁 Script executed:

cat -n core/ai-commit-msg/test/config.test.ts | head -50

Repository: stephansama/packages

Length of output: 1826


🏁 Script executed:

wc -l core/ai-commit-msg/test/config.test.ts

Repository: stephansama/packages

Length of output: 106


🏁 Script executed:

git -C core/ai-commit-msg log --oneline -n 20 -- test/config.test.ts

Repository: stephansama/packages

Length of output: 119


Replace blanket ESLint disable with a targeted rule instead.

The file disables unicorn/no-abusive-eslint-disable and then immediately uses /* eslint-disable */ to suppress all linting rules, which is exactly the anti-pattern the unicorn rule is designed to prevent. The problematic code uses as any type assertions on lines 26 and 39 when mocking cosmiconfig. Replace the blanket disable with:

/* eslint-disable `@typescript-eslint/no-explicit-any` */

Alternatively, add a rule-specific disable only at the lines that need it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/ai-commit-msg/test/config.test.ts` around lines 1 - 2, Replace the
blanket ESLint disable with a targeted rule: remove "/* eslint-disable */" and
instead use "/* eslint-disable `@typescript-eslint/no-explicit-any` */" at the top
of core/ai-commit-msg/test/config.test.ts, or alternatively remove the file-wide
disable and add inline rule-specific disables immediately where the cosmiconfig
mocks use "as any" (the mocks at the locations corresponding to the current
lines 26 and 39) so only the explicit-any rule is suppressed.

import { cosmiconfig } from "cosmiconfig";
import { afterEach, describe, expect, it, vi } from "vitest";

Expand Down
5 changes: 2 additions & 3 deletions core/ai-commit-msg/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,10 @@ describe("index run", () => {
);
});

it("should exit if provider initialization fails", () => {
it("should exit if provider initialization fails", async () => {
(getProvider as any).mockReturnValue(err(new Error("Provider error")));

// eslint-disable-next-line @typescript-eslint/no-floating-promises
expect(run()).rejects.toThrowError();
await expect(run()).rejects.toThrowError();
});

it("should skip run if skipNextRun is true", async () => {
Expand Down
24 changes: 15 additions & 9 deletions core/ai-commit-msg/test/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,16 @@ describe("schema", () => {
model: "gemini-2.5-flash",
provider: "google",
};

const result = configSchema.safeParse(config);

expect(result.success).toBe(true);
if (result.success) {
expect(result.data.prompt).toBe(defaultPrompt);
expect(result.data.useConventionalCommits).toBe(true);
expect(result.data.verbose).toBe(0);
}

if (!result.success) return;

expect(result.data.prompt).toBe(defaultPrompt);
expect(result.data.useConventionalCommits).toBe(true);
expect(result.data.verbose).toBe(0);
});

it("should parse full config", () => {
Expand All @@ -77,17 +80,20 @@ describe("schema", () => {
verbose: 2,
};
const result = configSchema.safeParse(config);

expect(result.success).toBe(true);
if (result.success) {
expect(result.data.prompt).toBe("custom prompt");
expect(result.data.verbose).toBe(2);
}

if (!result.success) return;

expect(result.data.prompt).toBe("custom prompt");
expect(result.data.verbose).toBe(2);
});

it("should fail if model is missing", () => {
const config = {
provider: "google",
};

const result = configSchema.safeParse(config);
expect(result.success).toBe(false);
});
Expand Down
4 changes: 2 additions & 2 deletions core/ai-commit-msg/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"extends": ["../../tsconfig.json"],
"include": ["./src/**/*"],
"extends": ["../../tsconfig.base.json"],
"include": ["./src/**/*", "vitest.config.ts", "build.ts", "./test/**/*"],
"compilerOptions": {
"types": ["node"]
}
Comment on lines 9 to 11

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Missing composite: true breaks the monorepo composite build setup.

All other packages in this PR enable compilerOptions.composite: true for incremental/project-references builds, but this file is missing that setting. This inconsistency will prevent this package from participating in the composite build graph.

🔧 Proposed fix to enable composite mode
   "compilerOptions": {
-    "types": ["node"]
+    "types": ["node"],
+    "composite": true
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"compilerOptions": {
"types": ["node"]
}
"compilerOptions": {
"types": ["node"],
"composite": true
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/ai-commit-msg/tsconfig.json` around lines 4 - 6, The tsconfig.json for
core/ai-commit-msg is missing compilerOptions.composite: true which prevents
this package from participating in the monorepo composite build; update the
tsconfig.json by adding "composite": true under "compilerOptions" so this
package supports incremental/project-references builds (match other packages
that set composite), and ensure the file still includes "types": ["node"]
alongside the new composite flag.

Expand Down
2 changes: 2 additions & 0 deletions core/alfred-kaomoji/jsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"compilerOptions": {
"allowJs": true,
"composite": true,
"noEmit": false,
"skipLibCheck": true
},
"include": ["./src/*.js"],
Expand Down
8 changes: 2 additions & 6 deletions core/astro-iconify-svgmap/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ import path from "node:path";
import type { Options } from "./type.ts";

import pkg from "../package.json";
import {
CONFIG_FILENAME,
defaultConfig,
LOADED_ICONS_FILENAME,
} from "./const.ts";
import { CONFIG_FILENAME, defaultConfig, LOADED_ICONS_FILENAME } from "./const";
import { buildEnd, generateSprite, loadIcons } from "./utilities";

const PLUGIN_NAME = pkg.name;
Expand All @@ -28,7 +24,7 @@ export function createIntegration(options_: Options = {}): AstroIntegration {
// eslint-disable-next-line perfectionist/sort-objects
hooks: {
async "astro:build:done"(_) {
console.log("starting build done");
console.info("starting build done");

const configFile = fs.readFileSync(
path.resolve(CONFIG_FILENAME),
Expand Down
7 changes: 4 additions & 3 deletions core/astro-iconify-svgmap/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"extends": ["../../tsconfig.json"],
"extends": ["../../tsconfig.base.json"],
"compilerOptions": {
"lib": ["DOM", "ESNext"],
"types": ["node"]
"types": ["node"],
"composite": true
},
"include": ["./src/**/*"]
"include": ["./src/**/*", "tsdown.config.ts"]
}
5 changes: 2 additions & 3 deletions core/auto-readme/build.mjs → core/auto-readme/build.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as fsp from "node:fs/promises";
import path from "node:path";
import { build as tsdown } from "tsdown";
import { build as tsdown, type UserConfig } from "tsdown";
import * as z from "zod";

const outputDirectory = path.resolve("./dist");
Expand All @@ -18,8 +18,7 @@ const jsonString = JSON.stringify(jsonSchema);

await fsp.writeFile(path.join(schemaDirectory, "schema.json"), jsonString);

/** @param {import("tsdown").InlineConfig} options */
function build(options) {
function build(options: UserConfig) {
return tsdown({
attw: { excludeEntrypoints: ["schema.json"] },
exports: true,
Expand Down
2 changes: 1 addition & 1 deletion core/auto-readme/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"mdast": "catalog:",
"mdast-comment-marker": "catalog:",
"mdast-util-from-markdown": "catalog:",
"mdast-zone": "github:stephansama/mdast-zone#1c5b08cd97240debeed4c9c6afad49df5877a132",
"mdast-zone": "catalog:",
"obug": "catalog:cli",
"pkg-types": "catalog:",
"remark": "catalog:",
Expand Down
1 change: 0 additions & 1 deletion core/auto-readme/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// eslint-disable-next-line e18e/ban-dependencies
import { cosmiconfig, getDefaultSearchPlaces, type Options } from "cosmiconfig";
import deepmerge from "deepmerge";
import * as toml from "smol-toml";
Expand Down
1 change: 0 additions & 1 deletion core/auto-readme/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ export const autoReadmeRemarkPlugin: Plugin<[Config, ActionData], Root> =
const body =
`${heading}\n` +
Object.entries(inputs)
// eslint-disable-next-line baseline-js/use-baseline
.toSorted((a) => (a[1].required ? -1 : 1))
.map(([key, value]) => {
return `- ${wrapRequired(value.required, key)}: (default: ${value.default})\n\n${value.description}`;
Expand Down
7 changes: 4 additions & 3 deletions core/auto-readme/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"extends": ["../../tsconfig.json"],
"include": ["./src/**/*"],
"extends": ["../../tsconfig.base.json"],
"include": ["./src/**/*", "build.ts", "cli.mjs"],
"compilerOptions": {
"types": ["./types/plugins.d.ts", "node"]
"types": ["./types/plugins.d.ts", "node"],
"composite": true
}
}
4 changes: 2 additions & 2 deletions core/catppuccin-jsonresume-theme/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"extends": ["../../tsconfig.json"],
"include": ["./src/**/*"],
"extends": ["../../tsconfig.base.json"],
"include": ["./src/**/*", "tsdown.config.ts"],
"compilerOptions": {
"types": ["node"]
}
Expand Down
7 changes: 5 additions & 2 deletions core/catppuccin-typedoc/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"extends": ["../../tsconfig.json"],
"extends": ["../../tsconfig.base.json"],
"include": ["./src/**/*"],
"compilerOptions": { "types": ["node"] }
"compilerOptions": {
"types": ["node"],
"composite": true
}
}
8 changes: 4 additions & 4 deletions core/catppuccin-xsl/src/opml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { flavors } from "@catppuccin/palette";
import { opmlSchema } from "@templates/schema";
import { minify } from "minify";

import * as utils from "./utils";
import * as utilities from "./utilities";

for (const [theme, val] of Object.entries(flavors)) {
const colors = utils.convertColors(val.colors);
for (const [theme, value] of Object.entries(flavors)) {
const colors = utilities.convertColors(value.colors);
const styleTemplate = await opmlSchema.compile("style", colors);
const style = await minify.css(styleTemplate);
const outputFile = await opmlSchema.compile("markup", { style });

await utils.writeFile(`opml-${theme}.xsl`, outputFile);
await utilities.writeFile(`opml-${theme}.xsl`, outputFile);
}
10 changes: 5 additions & 5 deletions core/catppuccin-xsl/src/rss.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import { rssSchema } from "@templates/schema";
import { minify } from "minify";

import pkg from "../package.json" with { type: "json" };
import * as utils from "./utils";
import * as utilities from "./utilities";

const lightColors = utils.convertColors(flavors.latte.colors);
const lightColors = utilities.convertColors(flavors.latte.colors);
const lightStyle = await rssSchema.compile("style", lightColors);
const darkThemes = Object.entries(flavors).filter(
([theme]) => theme !== "latte",
);

for (const [theme, val] of darkThemes) {
const colors = utils.convertColors(val.colors);
for (const [theme, value] of darkThemes) {
const colors = utilities.convertColors(value.colors);
const currentStyle = await rssSchema.compile("style", colors);
const currentComment = await rssSchema.compile("comment", {
package_name: pkg.name,
Expand All @@ -35,5 +35,5 @@ for (const [theme, val] of darkThemes) {
style,
});

await utils.writeFile(`rss-${theme}.xsl`, xml);
await utilities.writeFile(`rss-${theme}.xsl`, xml);
}
6 changes: 3 additions & 3 deletions core/catppuccin-xsl/src/run.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ vi.mock("node:fs/promises", async (importOriginal) => ({
}));

it("./opml.ts", async () => {
await expect(import("./opml.ts")).resolves.not.toThrow();
await expect(import("./opml")).resolves.not.toThrow();
});

it("./rss.ts", async () => {
await expect(import("./rss.ts")).resolves.not.toThrow();
await expect(import("./rss")).resolves.not.toThrow();
});

it("./sitemap.ts", async () => {
await expect(import("./sitemap.ts")).resolves.not.toThrow();
await expect(import("./sitemap")).resolves.not.toThrow();
});
10 changes: 5 additions & 5 deletions core/catppuccin-xsl/src/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ import { flavors } from "@catppuccin/palette";
import { sitemapSchema } from "@templates/schema";
import { minify } from "minify";

import * as utils from "./utils";
import * as utilities from "./utilities";

const lightColors = utils.convertColors(flavors.latte.colors);
const lightColors = utilities.convertColors(flavors.latte.colors);
const lightStyle = await sitemapSchema.compile("style", lightColors);
const darkThemes = Object.entries(flavors).filter(
([theme]) => theme !== "latte",
);

for (const [theme, val] of darkThemes) {
const colors = utils.convertColors(val.colors);
for (const [theme, value] of darkThemes) {
const colors = utilities.convertColors(value.colors);
const currentStyle = await sitemapSchema.compile("style", colors);
const themeStylesheet = await sitemapSchema.compile("themeStylesheet", {
darkStyle: currentStyle,
lightStyle,
});
const style = await minify.css(themeStylesheet);
const xml = await sitemapSchema.compile("markup", { style });
await utils.writeFile(`sitemap-${theme}.xsl`, xml);
await utilities.writeFile(`sitemap-${theme}.xsl`, xml);
}
Loading
Loading