jskelet 0.1.1

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.
Files changed (72) hide show
  1. package/AGENTS.md +127 -0
  2. package/CHANGELOG.md +40 -0
  3. package/LICENSE +21 -0
  4. package/README.md +342 -0
  5. package/bin/jskelet.mjs +104 -0
  6. package/docs/01-baslangic.md +285 -0
  7. package/docs/02-mimari.md +287 -0
  8. package/docs/03-routing.md +437 -0
  9. package/docs/04-render-ve-sablonlar.md +490 -0
  10. package/docs/05-islands.md +429 -0
  11. package/docs/06-cache.md +409 -0
  12. package/docs/07-yapilandirma.md +673 -0
  13. package/docs/08-build.md +366 -0
  14. package/docs/09-dev-araclari.md +302 -0
  15. package/docs/10-dagitim.md +329 -0
  16. package/docs/11-tasima.md +352 -0
  17. package/docs/README.md +82 -0
  18. package/package.json +97 -0
  19. package/src/build/build.mjs +138 -0
  20. package/src/build/ensure-build.mjs +15 -0
  21. package/src/build/paths.mjs +118 -0
  22. package/src/build/resolve-peer.mjs +36 -0
  23. package/src/build/tasks/client.mjs +268 -0
  24. package/src/build/tasks/css.mjs +124 -0
  25. package/src/build/tasks/fonts.mjs +146 -0
  26. package/src/build/tasks/icons.mjs +224 -0
  27. package/src/build/tasks/images.mjs +244 -0
  28. package/src/build/tasks/precompress.mjs +78 -0
  29. package/src/client/devtools/overlay.js +1763 -0
  30. package/src/client/devtools/report.html +185 -0
  31. package/src/client/devtools/report.js +712 -0
  32. package/src/client/dom.js +95 -0
  33. package/src/client/index.js +26 -0
  34. package/src/client/registry.js +223 -0
  35. package/src/client/safe-image.js +91 -0
  36. package/src/client/store.js +36 -0
  37. package/src/config/defaults.js +102 -0
  38. package/src/config/index.js +433 -0
  39. package/src/config/pattern.js +107 -0
  40. package/src/dev-server.mjs +383 -0
  41. package/src/http/control-flow.js +56 -0
  42. package/src/http/request-cache.js +46 -0
  43. package/src/index.js +35 -0
  44. package/src/init.mjs +220 -0
  45. package/src/log.mjs +332 -0
  46. package/src/logo.png +0 -0
  47. package/src/runtime/alias-hooks.mjs +119 -0
  48. package/src/runtime/register.mjs +4 -0
  49. package/src/server/assets.js +119 -0
  50. package/src/server/create-app.js +167 -0
  51. package/src/server/dev/devtools.js +383 -0
  52. package/src/server/dev/report.js +351 -0
  53. package/src/server/head-hints.js +132 -0
  54. package/src/server/html-cache.js +166 -0
  55. package/src/server/metadata.js +102 -0
  56. package/src/server/middleware/compression.js +205 -0
  57. package/src/server/middleware/dev-gate.js +62 -0
  58. package/src/server/middleware/headers.js +37 -0
  59. package/src/server/middleware/redirects.js +32 -0
  60. package/src/server/middleware/static-precompressed.js +100 -0
  61. package/src/server/middleware/upstream-proxy.js +141 -0
  62. package/src/server/prewarm.js +283 -0
  63. package/src/server/render.js +356 -0
  64. package/src/server/router.js +121 -0
  65. package/src/server/status-page.js +164 -0
  66. package/src/server/upstream-tracking.js +51 -0
  67. package/src/start.mjs +7 -0
  68. package/src/templates/layout.ejs +44 -0
  69. package/src/version.mjs +17 -0
  70. package/src/views/components/loader.js +85 -0
  71. package/src/views/helpers/html.js +102 -0
  72. package/src/views/helpers/tags.js +193 -0
@@ -0,0 +1,193 @@
1
+ /**
2
+ * `next/link`, `next/image` ve `@phosphor-icons/react` karşılıkları.
3
+ * Hepsi HTML string döndürür; EJS içinden `<%- %>` ile basılır.
4
+ */
5
+ import { attrs, esc, cn } from "./html.js";
6
+ import { asset, getSpriteIds, optimizedImage } from "../../server/assets.js";
7
+
8
+ const isDev = process.env.NODE_ENV === "development";
9
+
10
+ /** Aynı eksik ikon için tek uyarı. */
11
+ const warnedIcons = new Set();
12
+
13
+ /**
14
+ * `SeoLink` karşılığı: title otomatik doldurulur.
15
+ * @param {{ href: string, text?: string, html?: string, class?: string,
16
+ * title?: string, ariaLabel?: string, target?: string, rel?: string,
17
+ * attrs?: Record<string, unknown> }} props
18
+ * @returns {string}
19
+ */
20
+ export function link(props) {
21
+ const {
22
+ href,
23
+ text,
24
+ html,
25
+ class: className,
26
+ title,
27
+ ariaLabel,
28
+ target,
29
+ rel,
30
+ attrs: extra = {},
31
+ } = props;
32
+
33
+ const resolvedTitle = title ?? ariaLabel ?? text ?? href;
34
+ const isExternal = /^https?:\/\//.test(String(href ?? ""));
35
+
36
+ const attributes = attrs({
37
+ href,
38
+ class: className,
39
+ title: resolvedTitle,
40
+ "aria-label": ariaLabel,
41
+ target: target ?? (isExternal ? "_blank" : undefined),
42
+ rel: rel ?? (isExternal ? "noopener noreferrer" : undefined),
43
+ ...extra,
44
+ });
45
+
46
+ return `<a${attributes}>${html ?? esc(text ?? "")}</a>`;
47
+ }
48
+
49
+ /**
50
+ * `next/image` karşılığı. `public/` altındaki yerel görseller için build'de
51
+ * üretilen webp varyantları (`build/tasks/images.mjs`) otomatik olarak
52
+ * `srcset` + intrinsic `width`/`height` olarak eklenir; manifest'te olmayan
53
+ * ya da uzak görseller olduğu gibi basılır.
54
+ *
55
+ * `priority` LCP görselleri için `fetchpriority=high` + eager yükleme yapar.
56
+ * @param {{ src: string, alt: string, width?: number, height?: number,
57
+ * class?: string, sizes?: string, srcset?: string, priority?: boolean,
58
+ * fill?: boolean, loading?: 'lazy' | 'eager', unoptimized?: boolean,
59
+ * attrs?: Record<string, unknown> }} props
60
+ * @returns {string}
61
+ */
62
+ export function image(props) {
63
+ const {
64
+ src,
65
+ alt,
66
+ width,
67
+ height,
68
+ class: className,
69
+ sizes,
70
+ srcset,
71
+ priority = false,
72
+ fill = false,
73
+ loading,
74
+ unoptimized = false,
75
+ attrs: extra = {},
76
+ } = props;
77
+
78
+ const optimized = unoptimized || srcset ? undefined : optimizedImage(src);
79
+ const largest = optimized?.variants.at(-1);
80
+ // Tek varyant üretilmişse (kaynak zaten küçükse) srcset/sizes gürültüden ibaret.
81
+ const responsive = optimized && optimized.variants.length > 1;
82
+
83
+ const attributes = attrs({
84
+ src: largest?.url ?? src,
85
+ alt: alt ?? "",
86
+ width: fill ? undefined : (width ?? optimized?.width),
87
+ height: fill ? undefined : (height ?? optimized?.height),
88
+ class: fill
89
+ ? cn("absolute inset-0 h-full w-full object-cover", className)
90
+ : className,
91
+ sizes: responsive ? (sizes ?? defaultSizes(optimized)) : sizes,
92
+ srcset: responsive ? toSrcSet(optimized) : srcset,
93
+ loading: loading ?? (priority ? "eager" : "lazy"),
94
+ decoding: priority ? "sync" : "async",
95
+ fetchpriority: priority ? "high" : undefined,
96
+ ...extra,
97
+ });
98
+
99
+ return `<img${attributes}>`;
100
+ }
101
+
102
+ /**
103
+ * @param {import("../../server/assets.js").OptimizedImage} optimized
104
+ * @returns {string}
105
+ */
106
+ function toSrcSet(optimized) {
107
+ return optimized.variants
108
+ .map((variant) => `${variant.url} ${variant.width}w`)
109
+ .join(", ");
110
+ }
111
+
112
+ /**
113
+ * Çağıran `sizes` vermediyse makul bir varsayılan: görsel kendi intrinsic
114
+ * genişliğinden büyütülmez, dar ekranlarda viewport'u kaplar.
115
+ * @param {import("../../server/assets.js").OptimizedImage} optimized
116
+ * @returns {string}
117
+ */
118
+ function defaultSizes(optimized) {
119
+ const max = optimized.variants.at(-1)?.width ?? optimized.width;
120
+ return `(max-width: ${max}px) 100vw, ${max}px`;
121
+ }
122
+
123
+ /**
124
+ * LCP görselleri için `<head>` preload etiketi.
125
+ * @param {{ href: string, imagesrcset?: string, imagesizes?: string }} props
126
+ * @returns {string}
127
+ */
128
+ export function preloadImage({ href, imagesrcset, imagesizes }) {
129
+ return `<link${attrs({
130
+ rel: "preload",
131
+ as: "image",
132
+ href,
133
+ imagesrcset,
134
+ imagesizes,
135
+ fetchpriority: "high",
136
+ })}>`;
137
+ }
138
+
139
+ /**
140
+ * Phosphor ikonları — build zamanı üretilen SVG sprite'tan `<use>`.
141
+ * `weight` sprite id'sine dahildir (regular/bold/fill).
142
+ * @param {{ name: string, size?: number | string, weight?: string,
143
+ * class?: string, attrs?: Record<string, unknown> }} props
144
+ * @returns {string}
145
+ */
146
+ export function icon(props) {
147
+ const {
148
+ name,
149
+ size = 24,
150
+ weight = "regular",
151
+ class: className,
152
+ attrs: extra = {},
153
+ } = props;
154
+
155
+ const spritePath = asset("sprite.svg");
156
+ const id = `${toKebab(name)}-${weight}`;
157
+
158
+ if (isDev && !warnedIcons.has(id)) {
159
+ const ids = getSpriteIds();
160
+ if (ids.size && !ids.has(id)) {
161
+ warnedIcons.add(id);
162
+ console.warn(
163
+ `[icon] sprite'ta yok: ${id} — adı sabit yazın ya da build/tasks/icons.mjs taramasına ekleyin.`,
164
+ );
165
+ }
166
+ }
167
+
168
+ const attributes = attrs({
169
+ width: size,
170
+ height: size,
171
+ class: className,
172
+ "aria-hidden": "true",
173
+ focusable: "false",
174
+ fill: "currentColor",
175
+ viewBox: "0 0 256 256",
176
+ ...extra,
177
+ });
178
+
179
+ return `<svg${attributes}><use href="${esc(spritePath)}#${esc(id)}"></use></svg>`;
180
+ }
181
+
182
+ /**
183
+ * `ArrowRightIcon` / `ArrowRight` → `arrow-right`
184
+ * @param {string} name
185
+ * @returns {string}
186
+ */
187
+ export function toKebab(name) {
188
+ return String(name)
189
+ .replace(/Icon$/, "")
190
+ .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
191
+ .replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2")
192
+ .toLowerCase();
193
+ }