xenopomp-essentials 0.5.0-canary.4 → 0.5.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1,76 @@
1
- import s from"node:path";import{z as r}from"zod";const i=r.object({dirname:r.string().optional()}),h=i.parse(import.meta);class a{paths=[];pushPaths(...t){return this.paths.push(...t),this}cd(...t){return this.pushPaths(...t)}file(t){return this.pushPaths(`./${t}`)}appSource(){return h.dirname?this.pushPaths(s.join(s.dirname(h.dirname),"../")):this.cwd()}cwd(){return this.pushPaths(process.cwd())}clear(){return this.paths=[],this}build(){return s.join(...this.paths)}}export{a as PathBuilder};
1
+ import path from 'node:path';
2
+ import { z } from 'zod';
3
+ import dotenv from 'dotenv';
4
+
5
+ const importMetaSchema = z.object({
6
+ dirname: z.string().optional()
7
+ });
8
+ const importMeta = importMetaSchema.parse(import.meta);
9
+
10
+ dotenv.config({ quiet: true });
11
+ const envSchema = z.object({
12
+ DISABLE_MINIFY: z.string().transform((arg) => arg === "true")
13
+ });
14
+ envSchema.parse(process.env);
15
+
16
+ class PathBuilder {
17
+ paths = [];
18
+ pushPaths(...paths) {
19
+ this.paths.push(...paths);
20
+ return this;
21
+ }
22
+ /**
23
+ * Pushes any custom paths to builder.
24
+ * @since 0.0.1
25
+ * @param paths
26
+ */
27
+ cd(...paths) {
28
+ return this.pushPaths(...paths);
29
+ }
30
+ /**
31
+ * Pushes filename to paths.
32
+ * @since 0.0.1
33
+ * @param fileName
34
+ */
35
+ file(fileName) {
36
+ return this.pushPaths(`./${fileName}`);
37
+ }
38
+ /**
39
+ * Pushes path to compiled app directory.
40
+ * Is useful for cli tools that have to access files inside their bundles.
41
+ *
42
+ * It probably may take no effect (if import.meta is not available in a scope).
43
+ * If it is, will push cwd.
44
+ *
45
+ * @since 0.0.1
46
+ */
47
+ appSource() {
48
+ if (!importMeta.dirname) {
49
+ return this.cwd();
50
+ }
51
+ return this.pushPaths(path.join(path.dirname(importMeta.dirname), "../"));
52
+ }
53
+ /**
54
+ * Gets path of directory where script is running. In cli tools it access
55
+ * path, where cli tool was started.
56
+ * @since 0.0.1
57
+ */
58
+ cwd() {
59
+ return this.pushPaths(process.cwd());
60
+ }
61
+ /**
62
+ * @since 0.0.1
63
+ */
64
+ clear() {
65
+ this.paths = [];
66
+ return this;
67
+ }
68
+ /**
69
+ * @since 0.0.1
70
+ */
71
+ build() {
72
+ return path.join(...this.paths);
73
+ }
74
+ }
75
+
76
+ export { PathBuilder };
package/eslint/index.mjs CHANGED
@@ -1 +1,303 @@
1
- import{GLOB_JSX as a,GLOB_TSX as i,interopDefault as f,GLOB_MARKDOWN_CODE as p,antfu as c}from"@antfu/eslint-config";import{deepmerge as o}from"deepmerge-ts";import s from"globals";import l from"eslint-plugin-prettier/recommended";import{fixupPluginRules as u}from"@eslint/compat";import m from"eslint-plugin-deprecation";const d="XenoPOMP",t=d.toLowerCase();async function x(){return[{files:[a,i],name:`${t}:react`,rules:{"react-refresh/only-export-components":"off","react/no-clone-element":"off","react/no-missing-component-display-name":"off"}}]}async function y(){const e=await f(import("@next/eslint-plugin-next"));return[{name:`${t}:next`,plugins:{"@next/next":e},rules:{"@next/next/google-font-display":"warn","@next/next/google-font-preconnect":"warn","@next/next/next-script-for-ga":"warn","@next/next/no-async-client-component":"warn","@next/next/no-before-interactive-script-outside-document":"warn","@next/next/no-css-tags":"warn","@next/next/no-head-element":"warn","@next/next/no-html-link-for-pages":"warn","@next/next/no-img-element":"warn","@next/next/no-page-custom-font":"warn","@next/next/no-styled-jsx-in-document":"warn","@next/next/no-sync-scripts":"warn","@next/next/no-title-in-document-head":"warn","@next/next/no-typos":"warn","@next/next/no-unwanted-polyfillio":"warn","@next/next/inline-script-id":"error","@next/next/no-assign-module-variable":"error","@next/next/no-document-import-in-page":"error","@next/next/no-duplicate-head":"error","@next/next/no-head-import-in-document":"error","@next/next/no-script-component-in-head":"error"}}]}async function g(){return[{name:`${t}:markdown`,files:[p],rules:{"import/no-unresolved":"off","unused-imports/no-unused-imports":"off","unused-imports/no-unused-vars":"off","no-alert":"off","no-console":"off","no-restricted-imports":"off","no-undef":"off","no-unused-expressions":"off","no-unused-vars":"off","antfu/no-cjs-exports":"off","antfu/no-ts-export-equal":"off","ts/no-redeclare":"off","ts/no-unused-vars":"off","ts/no-var-requires":"off","ts/consistent-type-imports":"off"}}]}async function w(){return[{name:`${t}:all`,rules:{"antfu/no-cjs-exports":"off","import/prefer-default-export":"off","import/extensions":"off","no-restricted-globals":"off","node/prefer-global/process":"off","jsonc/comma-dangle":"off","style/jsx-quotes":["error","prefer-double"],"style/jsx-one-expression-per-line":["error",{allow:"single-line"}],"style/arrow-parens":["error","as-needed"],"unused-imports/no-unused-imports":"error","unused-imports/no-unused-vars":["warn",{vars:"all",varsIgnorePattern:"^_",args:"after-used",argsIgnorePattern:"^_"}],"@stylistic/indent":["error",2,{ArrayExpression:1,CallExpression:{arguments:1},flatTernaryExpressions:!1,FunctionDeclaration:{body:1,parameters:1},FunctionExpression:{body:1,parameters:1},ignoreComments:!1,ignoredNodes:["TemplateLiteral *","TSIntersectionType","TSTypeParameterInstantiation","FunctionExpression > .params[decorators.length > 0]","FunctionExpression > .params > :matches(Decorator, :not(:first-child))","ClassBody.body > PropertyDefinition[decorators.length > 0] > .key"],ImportDeclaration:1,MemberExpression:1,ObjectExpression:1,offsetTernaryExpressions:!0,outerIIFEBody:1,SwitchCase:1,VariableDeclarator:1}]}}]}async function h(){return[{name:`${t}:old_config`,languageOptions:{globals:{...s.browser,...s.jquery,...s.node,document:"readonly",navigator:"readonly",window:"readonly"}},ignores:["**/.next/*","**/node_modules/*","**/.github/*","cypress","**/__tests__/e2e/*","*.json","**/*.d.ts",".eslintrc.js","eslint.config.js",".prettierrc",".stylelintrc.js","tsconfig.json","package.json","*.md","*.config.ts","*.config.js","*.md"]},{name:`${t}:rules_breakup_1`,rules:{"@next/next/no-duplicate-head":"off"}},{name:`${t}:rules_breakup_2`,rules:{"style/operator-linebreak":"off","test/consistent-test-it":"off","test/prefer-lowercase-title":"off","style/jsx-quotes":"off","style/multiline-ternary":"off","style/indent":"off"},ignores:["cypress"]},{name:`${t}:prettier`,rules:{"antfu/if-newline":"off"}}]}async function j(){return[l]}async function _(e,r){return[{name:"Deprecation plugin",languageOptions:{parserOptions:{project:r?.tsconfigPath??"./tsconfig.json",projectSource:!0}},plugins:{deprecation:u(m)},rules:{"deprecation/deprecation":e},files:["**/*.ts","**/*.tsx"]}]}function b(e,...r){const n=[];return e={...e,react:o(!0,e?.react),vue:o(!1,e?.vue),jsonc:o(!1,e?.jsonc),yaml:o(!1,e?.yaml),stylistic:o({semi:!0,quotes:"single"},e?.stylistic),typescript:o({overrides:{"ts/consistent-type-definitions":["error","interface"],"ts/interface-name-prefix":"off","ts/explicit-function-return-type":"off","ts/explicit-module-boundary-types":"off","ts/no-explicit-any":"off"}},e?.typescript),rules:o({"import/order":"off","react/react-in-jsx-scope":"off","react/prop-types":"off","antfu/top-level-function":"off","perfectionist/sort-imports":"off","perfectionist/sort-named-imports":"off","perfectionist/sort-named-exports":"off","antfu/consistent-chaining":"off","perfectionist/sort-exports":"off","style/no-multiple-empty-lines":"off"},e?.rules),deprecation:e?.deprecation,tsconfigPath:e?.tsconfigPath},(e.react??!0)&&n.push(x()),(e.all??!0)&&n.push(w()),(e.next??!1)&&n.push(y()),(e.markdown??!0)&&n.push(g()),e?.deprecation&&n.push(_(e?.deprecation??"warn",{tsconfigPath:e?.tsconfigPath})),n.push(h()),n.push(j()),c(e,...n,...r)}export{b as default};
1
+ import { GLOB_JSX, GLOB_TSX, interopDefault, GLOB_MARKDOWN_CODE, antfu } from '@antfu/eslint-config';
2
+ import { deepmerge } from 'deepmerge-ts';
3
+ import globals from 'globals';
4
+ import recommended from 'eslint-plugin-prettier/recommended';
5
+ import { fixupPluginRules } from '@eslint/compat';
6
+ import plugin from 'eslint-plugin-deprecation';
7
+
8
+ const AUTHOR_NAME = "XenoPOMP";
9
+ const AUTHOR_NAME_LOWER = AUTHOR_NAME.toLowerCase();
10
+
11
+ async function react() {
12
+ return [
13
+ {
14
+ files: [GLOB_JSX, GLOB_TSX],
15
+ name: `${AUTHOR_NAME_LOWER}:react`,
16
+ rules: {
17
+ "react-refresh/only-export-components": "off",
18
+ "react/no-clone-element": "off",
19
+ "react/no-missing-component-display-name": "off"
20
+ }
21
+ }
22
+ ];
23
+ }
24
+
25
+ async function next() {
26
+ const next2 = await interopDefault(import('@next/eslint-plugin-next'));
27
+ return [
28
+ {
29
+ name: `${AUTHOR_NAME_LOWER}:next`,
30
+ plugins: { "@next/next": next2 },
31
+ rules: {
32
+ "@next/next/google-font-display": "warn",
33
+ "@next/next/google-font-preconnect": "warn",
34
+ "@next/next/next-script-for-ga": "warn",
35
+ "@next/next/no-async-client-component": "warn",
36
+ "@next/next/no-before-interactive-script-outside-document": "warn",
37
+ "@next/next/no-css-tags": "warn",
38
+ "@next/next/no-head-element": "warn",
39
+ "@next/next/no-html-link-for-pages": "warn",
40
+ "@next/next/no-img-element": "warn",
41
+ "@next/next/no-page-custom-font": "warn",
42
+ "@next/next/no-styled-jsx-in-document": "warn",
43
+ "@next/next/no-sync-scripts": "warn",
44
+ "@next/next/no-title-in-document-head": "warn",
45
+ "@next/next/no-typos": "warn",
46
+ "@next/next/no-unwanted-polyfillio": "warn",
47
+ // errors
48
+ "@next/next/inline-script-id": "error",
49
+ "@next/next/no-assign-module-variable": "error",
50
+ "@next/next/no-document-import-in-page": "error",
51
+ "@next/next/no-duplicate-head": "error",
52
+ "@next/next/no-head-import-in-document": "error",
53
+ "@next/next/no-script-component-in-head": "error"
54
+ }
55
+ }
56
+ ];
57
+ }
58
+
59
+ async function markdown() {
60
+ return [
61
+ {
62
+ name: `${AUTHOR_NAME_LOWER}:markdown`,
63
+ files: [GLOB_MARKDOWN_CODE],
64
+ rules: {
65
+ "import/no-unresolved": "off",
66
+ "unused-imports/no-unused-imports": "off",
67
+ "unused-imports/no-unused-vars": "off",
68
+ "no-alert": "off",
69
+ "no-console": "off",
70
+ "no-restricted-imports": "off",
71
+ "no-undef": "off",
72
+ "no-unused-expressions": "off",
73
+ "no-unused-vars": "off",
74
+ "antfu/no-cjs-exports": "off",
75
+ "antfu/no-ts-export-equal": "off",
76
+ "ts/no-redeclare": "off",
77
+ "ts/no-unused-vars": "off",
78
+ "ts/no-var-requires": "off",
79
+ "ts/consistent-type-imports": "off"
80
+ }
81
+ }
82
+ ];
83
+ }
84
+
85
+ async function all() {
86
+ return [
87
+ {
88
+ name: `${AUTHOR_NAME_LOWER}:all`,
89
+ rules: {
90
+ "antfu/no-cjs-exports": "off",
91
+ "import/prefer-default-export": "off",
92
+ "import/extensions": "off",
93
+ "no-restricted-globals": "off",
94
+ "node/prefer-global/process": "off",
95
+ "jsonc/comma-dangle": "off",
96
+ "style/jsx-quotes": ["error", "prefer-double"],
97
+ "style/jsx-one-expression-per-line": [
98
+ "error",
99
+ { allow: "single-line" }
100
+ ],
101
+ "style/arrow-parens": ["error", "as-needed"],
102
+ "unused-imports/no-unused-imports": "error",
103
+ "unused-imports/no-unused-vars": [
104
+ "warn",
105
+ {
106
+ vars: "all",
107
+ varsIgnorePattern: "^_",
108
+ args: "after-used",
109
+ argsIgnorePattern: "^_"
110
+ }
111
+ ],
112
+ "@stylistic/indent": [
113
+ "error",
114
+ 2,
115
+ {
116
+ ArrayExpression: 1,
117
+ CallExpression: {
118
+ arguments: 1
119
+ },
120
+ flatTernaryExpressions: false,
121
+ FunctionDeclaration: {
122
+ body: 1,
123
+ parameters: 1
124
+ },
125
+ FunctionExpression: {
126
+ body: 1,
127
+ parameters: 1
128
+ },
129
+ ignoreComments: false,
130
+ ignoredNodes: [
131
+ "TemplateLiteral *",
132
+ "TSIntersectionType",
133
+ "TSTypeParameterInstantiation",
134
+ "FunctionExpression > .params[decorators.length > 0]",
135
+ "FunctionExpression > .params > :matches(Decorator, :not(:first-child))",
136
+ "ClassBody.body > PropertyDefinition[decorators.length > 0] > .key"
137
+ ],
138
+ ImportDeclaration: 1,
139
+ MemberExpression: 1,
140
+ ObjectExpression: 1,
141
+ offsetTernaryExpressions: true,
142
+ outerIIFEBody: 1,
143
+ SwitchCase: 1,
144
+ VariableDeclarator: 1
145
+ }
146
+ ]
147
+ }
148
+ }
149
+ ];
150
+ }
151
+
152
+ async function old() {
153
+ return [
154
+ {
155
+ name: `${AUTHOR_NAME_LOWER}:old_config`,
156
+ languageOptions: {
157
+ globals: {
158
+ ...globals.browser,
159
+ ...globals.jquery,
160
+ ...globals.node,
161
+ // Rewrite globals anyway
162
+ document: "readonly",
163
+ navigator: "readonly",
164
+ window: "readonly"
165
+ }
166
+ },
167
+ // Ignore patterns
168
+ ignores: [
169
+ "**/.next/*",
170
+ "**/node_modules/*",
171
+ "**/.github/*",
172
+ "cypress",
173
+ "**/__tests__/e2e/*",
174
+ "*.json",
175
+ "**/*.d.ts",
176
+ ".eslintrc.js",
177
+ "eslint.config.js",
178
+ ".prettierrc",
179
+ ".stylelintrc.js",
180
+ "tsconfig.json",
181
+ "package.json",
182
+ "*.md",
183
+ "*.config.ts",
184
+ "*.config.js",
185
+ "*.md"
186
+ ]
187
+ },
188
+ {
189
+ name: `${AUTHOR_NAME_LOWER}:rules_breakup_1`,
190
+ rules: { "@next/next/no-duplicate-head": "off" }
191
+ },
192
+ {
193
+ name: `${AUTHOR_NAME_LOWER}:rules_breakup_2`,
194
+ rules: {
195
+ "style/operator-linebreak": "off",
196
+ "test/consistent-test-it": "off",
197
+ "test/prefer-lowercase-title": "off",
198
+ "style/jsx-quotes": "off",
199
+ "style/multiline-ternary": "off",
200
+ "style/indent": "off"
201
+ },
202
+ ignores: ["cypress"]
203
+ },
204
+ {
205
+ name: `${AUTHOR_NAME_LOWER}:prettier`,
206
+ rules: {
207
+ "antfu/if-newline": "off"
208
+ }
209
+ }
210
+ ];
211
+ }
212
+
213
+ async function prettier() {
214
+ return [recommended];
215
+ }
216
+
217
+ async function deprecation(severity, options) {
218
+ return [
219
+ {
220
+ name: "Deprecation plugin",
221
+ languageOptions: {
222
+ parserOptions: {
223
+ project: options?.tsconfigPath ?? "./tsconfig.json",
224
+ projectSource: true
225
+ }
226
+ },
227
+ plugins: {
228
+ // @ts-expect-error Wrong library types
229
+ deprecation: fixupPluginRules(plugin)
230
+ },
231
+ rules: {
232
+ "deprecation/deprecation": severity
233
+ },
234
+ files: ["**/*.ts", "**/*.tsx"]
235
+ }
236
+ ];
237
+ }
238
+
239
+ function xenopomp(options, ...userConfigs) {
240
+ const configs = [];
241
+ options = {
242
+ ...options,
243
+ react: deepmerge(true, options?.react),
244
+ vue: deepmerge(
245
+ false,
246
+ options?.vue
247
+ ),
248
+ jsonc: deepmerge(false, options?.jsonc),
249
+ yaml: deepmerge(false, options?.yaml),
250
+ stylistic: deepmerge(
251
+ {
252
+ semi: true,
253
+ quotes: "single"
254
+ },
255
+ options?.stylistic
256
+ ),
257
+ typescript: deepmerge(
258
+ {
259
+ overrides: {
260
+ "ts/consistent-type-definitions": ["error", "interface"],
261
+ "ts/interface-name-prefix": "off",
262
+ "ts/explicit-function-return-type": "off",
263
+ "ts/explicit-module-boundary-types": "off",
264
+ "ts/no-explicit-any": "off"
265
+ }
266
+ },
267
+ options?.typescript
268
+ ),
269
+ rules: deepmerge(
270
+ {
271
+ "import/order": "off",
272
+ "react/react-in-jsx-scope": "off",
273
+ "react/prop-types": "off",
274
+ "antfu/top-level-function": "off",
275
+ "perfectionist/sort-imports": "off",
276
+ "perfectionist/sort-named-imports": "off",
277
+ "perfectionist/sort-named-exports": "off",
278
+ "antfu/consistent-chaining": "off",
279
+ "perfectionist/sort-exports": "off",
280
+ "style/no-multiple-empty-lines": "off"
281
+ },
282
+ options?.rules
283
+ ),
284
+ deprecation: options?.deprecation,
285
+ tsconfigPath: options?.tsconfigPath
286
+ };
287
+ if (options.react ?? true) configs.push(react());
288
+ if (options.all ?? true) configs.push(all());
289
+ if (options.next ?? false) configs.push(next());
290
+ if (options.markdown ?? true) configs.push(markdown());
291
+ if (options?.deprecation) {
292
+ configs.push(
293
+ deprecation(options?.deprecation ?? "warn", {
294
+ tsconfigPath: options?.tsconfigPath
295
+ })
296
+ );
297
+ }
298
+ configs.push(old());
299
+ configs.push(prettier());
300
+ return antfu(options, ...configs, ...userConfigs);
301
+ }
302
+
303
+ export { xenopomp as default };
package/index.mjs CHANGED
@@ -1 +1,45 @@
1
- import{transliterate as a}from"transliteration";function i(t){function r(n){return t(n)}return r.pipe=n=>i(e=>n(t(e))),r}function o(t){return t.charAt(0).toUpperCase()+t.slice(1)}function c(t){return t.charAt(0).toLowerCase()+t.slice(1)}const s=t=>{const r=t.match(/(\d\.){2}\d/gi)?.at(0)||null,n=t.match(/(?<=-)\w+(?=\.\d)/gi)?.at(0),e=t.match(/(?<=((\d\.){2}\d-\w+\.))\d+/gi)?.at(0);return{version:r,preid:n,prerelease:e}},p=a,u=(t,[r,n])=>r&&t<=r?r:n&&t>=n?n:t;function l(t,r){return Object.assign(t,r)}export{o as capitalize,l as jsxDotNotation,u as minmax,s as parseVersion,i as pipe,p as transliterate,c as uncapitalize};
1
+ import { transliterate as transliterate$1 } from 'transliteration';
2
+
3
+ function pipe(fn) {
4
+ function run(a) {
5
+ return fn(a);
6
+ }
7
+ run.pipe = (fn2) => pipe((a) => fn2(fn(a)));
8
+ return run;
9
+ }
10
+
11
+ function capitalize(str) {
12
+ return str.charAt(0).toUpperCase() + str.slice(1);
13
+ }
14
+ function uncapitalize(str) {
15
+ return str.charAt(0).toLowerCase() + str.slice(1);
16
+ }
17
+
18
+ const parseVersion = (raw) => {
19
+ const version = raw.match(/(\d\.){2}\d/gi)?.at(0) || null;
20
+ const preid = raw.match(/(?<=-)\w+(?=\.\d)/gi)?.at(0);
21
+ const prerelease = raw.match(/(?<=((\d\.){2}\d-\w+\.))\d+/gi)?.at(0);
22
+ return {
23
+ version,
24
+ preid,
25
+ prerelease
26
+ };
27
+ };
28
+
29
+ const transliterate = transliterate$1;
30
+
31
+ const minmax = (num, [min, max]) => {
32
+ if (!!min && num <= min) {
33
+ return min;
34
+ }
35
+ if (!!max && num >= max) {
36
+ return max;
37
+ }
38
+ return num;
39
+ };
40
+
41
+ function jsxDotNotation(comp, rest) {
42
+ return Object.assign(comp, rest);
43
+ }
44
+
45
+ export { capitalize, jsxDotNotation, minmax, parseVersion, pipe, transliterate, uncapitalize };
package/next/index.mjs CHANGED
@@ -1,11 +1,39 @@
1
- import r from"next/script";const n=()=>React.createElement("script",{src:"https://unpkg.com/react-scan/dist/auto.global.js",async:!0}),i=({id:t,clickMap:e=!0,trackLinks:a=!0,accurateTrackBounce:c=!0})=>React.createElement(r,{id:"metrika-counter",strategy:"afterInteractive"},` (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
1
+ import Script from 'next/script';
2
+
3
+ const ReactScan = () => {
4
+ return /* @__PURE__ */ React.createElement(
5
+ "script",
6
+ {
7
+ src: "https://unpkg.com/react-scan/dist/auto.global.js",
8
+ async: true
9
+ }
10
+ );
11
+ };
12
+
13
+ const Metrika = ({
14
+ id,
15
+ clickMap = true,
16
+ trackLinks = true,
17
+ accurateTrackBounce = true
18
+ }) => {
19
+ return /* @__PURE__ */ React.createElement(
20
+ Script,
21
+ {
22
+ id: "metrika-counter",
23
+ strategy: "afterInteractive"
24
+ },
25
+ ` (function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
2
26
  m[i].l=1*new Date();
3
27
  for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
4
28
  k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
5
29
  (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
6
30
 
7
- ym(${t}, "init", {
8
- clickmap:${e},
9
- trackLinks:${a},
10
- accurateTrackBounce:${c}
11
- });`);export{i as Metrika,n as ReactScan};
31
+ ym(${id}, "init", {
32
+ clickmap:${clickMap},
33
+ trackLinks:${trackLinks},
34
+ accurateTrackBounce:${accurateTrackBounce}
35
+ });`
36
+ );
37
+ };
38
+
39
+ export { Metrika, ReactScan };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xenopomp-essentials",
3
- "version": "0.5.0-canary.4",
3
+ "version": "0.5.0-rc.0",
4
4
  "author": "XenoPOMP <101574433+XenoPOMP@users.noreply.github.com>",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -56,6 +56,7 @@
56
56
  "@vitest/spy": "^4.0.14",
57
57
  "ansi-colors": "^4.1.3",
58
58
  "deepmerge-ts": "^7.1.5",
59
+ "dotenv": "^17.2.3",
59
60
  "eslint": "^9.22.0",
60
61
  "eslint-config-prettier": "^10.1.1",
61
62
  "eslint-plugin-deprecation": "^3.0.0",
package/vitest/index.mjs CHANGED
@@ -1 +1,121 @@
1
- import{expect as c,vi as t,afterEach as f,beforeAll as u,afterAll as h}from"vitest";import{render as d,renderHook as m}from"@testing-library/react";import l from"ansi-colors";import p from"vitest-matchmedia-mock";const a=e=>{c(()=>e()).not.toThrow()},b=(...e)=>{a(()=>d(...e))},C=(...e)=>{a(()=>m(...e))},k=e=>{t.stubEnv("CANONICAL_URL","http://localhost:4242"),t.stubEnv("IS_PRODUCTION","false"),e&&Object.entries(e).forEach(([o,n])=>t.stubEnv(o,n))},r=()=>{t.clearAllMocks(),t.resetAllMocks(),t.unstubAllEnvs(),t.unstubAllGlobals()},x=()=>{t.mock("next/navigation",()=>({useRouter:()=>({push(){}}),usePathname:()=>"/"}))},A={addBase:t.fn(),addComponents:t.fn(),addUtilities:t.fn(),addVariant:t.fn(),config:t.fn(),corePlugins:t.fn(),e:t.fn(),matchComponents:t.fn(),matchUtilities:t.fn(),matchVariant:t.fn(),theme:t.fn()};class g{_executionContext;constructor(o){this._executionContext=o}call(...o){console.debug(`${l.blue(`[${this._executionContext}]`)} ${l.green(`Custom spy is called with these args: ${l.blueBright(o.map(n=>`${n}`).join(", "))}`)}`)}}function v(e){const o=new g(e),n=t.spyOn(o,"call");return{expectToBeCalled:(...s)=>c(n).toHaveBeenCalledWith(s),expectToBeNotCalled:(...s)=>c(n).not.toHaveBeenCalledWith(s),spy:n,callSpy:(...s)=>o.call(s)}}const E=(e,o)=>{t.stubGlobal(e,o)},M={beforeAll:u,afterEach:f},i=(e,o="beforeAll")=>{let n;M[o](()=>n=e()),h(()=>{r(),n?.()})},y=()=>{const e=new p;i(()=>(e.clear(),()=>e.destroy()),"afterEach")};export{C as assertHookRendering,a as assertNotThrowing,b as assertRendering,r as clearMocks,y as injectMatchMediaMock,i as injectMocks,k as mockEnv,x as mockRouter,v as spyFactory,E as stubGlobal,A as twApiMock};
1
+ import { expect, vi, afterEach, beforeAll, afterAll } from 'vitest';
2
+ import { render, renderHook } from '@testing-library/react';
3
+ import c from 'ansi-colors';
4
+ import MatchMediaMock from 'vitest-matchmedia-mock';
5
+
6
+ const assertNotThrowing = (callable) => {
7
+ expect(() => callable()).not.toThrow();
8
+ };
9
+
10
+ const assertRendering = (...props) => {
11
+ assertNotThrowing(() => render(...props));
12
+ };
13
+ const assertHookRendering = (...props) => {
14
+ assertNotThrowing(() => renderHook(...props));
15
+ };
16
+
17
+ const mockEnv = (additionalMocks) => {
18
+ vi.stubEnv("CANONICAL_URL", "http://localhost:4242");
19
+ vi.stubEnv("IS_PRODUCTION", "false");
20
+ if (additionalMocks) {
21
+ Object.entries(additionalMocks).forEach(
22
+ ([key, value]) => vi.stubEnv(key, value)
23
+ );
24
+ }
25
+ };
26
+
27
+ const clearMocks = () => {
28
+ vi.clearAllMocks();
29
+ vi.resetAllMocks();
30
+ vi.unstubAllEnvs();
31
+ vi.unstubAllGlobals();
32
+ };
33
+
34
+ const mockRouter = () => {
35
+ vi.mock("next/navigation", () => {
36
+ return {
37
+ /** Mock implementation for useRouter */
38
+ useRouter: () => {
39
+ return {
40
+ /** Mock implementation for useRouter().push */
41
+ push() {
42
+ }
43
+ };
44
+ },
45
+ /** Mock implementation for usePathname */
46
+ usePathname: () => {
47
+ return "/";
48
+ }
49
+ };
50
+ });
51
+ };
52
+
53
+ const twApiMock = {
54
+ addBase: vi.fn(),
55
+ addComponents: vi.fn(),
56
+ addUtilities: vi.fn(),
57
+ addVariant: vi.fn(),
58
+ config: vi.fn(),
59
+ corePlugins: vi.fn(),
60
+ e: vi.fn(),
61
+ matchComponents: vi.fn(),
62
+ matchUtilities: vi.fn(),
63
+ matchVariant: vi.fn(),
64
+ theme: vi.fn()
65
+ };
66
+
67
+ class CustomSpyCaller {
68
+ _executionContext;
69
+ constructor(context) {
70
+ this._executionContext = context;
71
+ }
72
+ call(...args) {
73
+ console.debug(
74
+ `${c.blue(`[${this._executionContext}]`)} ${c.green(
75
+ `Custom spy is called with these args: ${c.blueBright(
76
+ args.map((s) => `${s}`).join(", ")
77
+ )}`
78
+ )}`
79
+ );
80
+ }
81
+ }
82
+ function spyFactory(context) {
83
+ const caller = new CustomSpyCaller(context);
84
+ const spy = vi.spyOn(caller, "call");
85
+ const expectToBeCalled = (...args) => expect(spy).toHaveBeenCalledWith(args);
86
+ const expectToBeNotCalled = (...args) => expect(spy).not.toHaveBeenCalledWith(args);
87
+ const callSpy = (...args) => caller.call(args);
88
+ return {
89
+ expectToBeCalled,
90
+ expectToBeNotCalled,
91
+ spy,
92
+ callSpy
93
+ };
94
+ }
95
+
96
+ const stubGlobal = (name, stub) => {
97
+ vi.stubGlobal(name, stub);
98
+ };
99
+
100
+ const strategies = {
101
+ beforeAll,
102
+ afterEach
103
+ };
104
+ const injectMocks = (func, strategy = "beforeAll") => {
105
+ let afterFn;
106
+ strategies[strategy](() => afterFn = func());
107
+ afterAll(() => {
108
+ clearMocks();
109
+ afterFn?.();
110
+ });
111
+ };
112
+
113
+ const injectMatchMediaMock = () => {
114
+ const matcher = new MatchMediaMock();
115
+ injectMocks(() => {
116
+ matcher.clear();
117
+ return () => matcher.destroy();
118
+ }, "afterEach");
119
+ };
120
+
121
+ export { assertHookRendering, assertNotThrowing, assertRendering, clearMocks, injectMatchMediaMock, injectMocks, mockEnv, mockRouter, spyFactory, stubGlobal, twApiMock };