jskelet 0.6.3 → 0.6.4
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/AGENTS.md +136 -136
- package/CHANGELOG.md +628 -620
- package/LICENSE +21 -21
- package/README.md +2 -0
- package/bin/jskelet.mjs +130 -130
- package/docs/01-baslangic.md +291 -291
- package/docs/02-mimari.md +310 -310
- package/docs/03-routing.md +515 -515
- package/docs/04-render-ve-sablonlar.md +667 -661
- package/docs/05-islands.md +486 -486
- package/docs/06-cache.md +1467 -1443
- package/docs/07-yapilandirma.md +1208 -1197
- package/docs/08-build.md +429 -429
- package/docs/09-dev-araclari.md +364 -364
- package/docs/10-dagitim.md +348 -338
- package/docs/12-panel-ve-oturum.md +479 -478
- package/docs/README.md +83 -83
- package/docs/en/01-getting-started.md +298 -298
- package/docs/en/02-architecture.md +329 -329
- package/docs/en/03-routing.md +531 -531
- package/docs/en/04-rendering.md +675 -669
- package/docs/en/05-islands.md +497 -497
- package/docs/en/06-caching.md +1476 -1453
- package/docs/en/07-configuration.md +1229 -1219
- package/docs/en/08-build.md +447 -447
- package/docs/en/09-dev-tools.md +373 -373
- package/docs/en/10-deployment.md +351 -340
- package/docs/en/11-migration.md +398 -398
- package/docs/en/12-dashboards-and-sessions.md +489 -488
- package/docs/en/README.md +87 -87
- package/package.json +137 -137
- package/src/build/ensure-build.mjs +19 -19
- package/src/build/paths.mjs +153 -153
- package/src/build/resolve-peer.mjs +36 -36
- package/src/build/tasks/client.mjs +349 -349
- package/src/build/tasks/css.mjs +235 -235
- package/src/build/tasks/fonts.mjs +146 -146
- package/src/build/tasks/icons.mjs +357 -357
- package/src/build/tasks/images.mjs +244 -244
- package/src/build/tasks/precompress.mjs +78 -78
- package/src/build/tasks/templates.mjs +20 -20
- package/src/client/admin/i18n.js +764 -764
- package/src/client/admin/login.html +74 -74
- package/src/client/admin/panel.css +809 -809
- package/src/client/admin/panel.html +495 -495
- package/src/client/admin/panel.js +1251 -1251
- package/src/client/devtools/report.html +185 -185
- package/src/client/devtools/report.js +745 -745
- package/src/client/devtools/seo.js +628 -628
- package/src/client/dom.js +95 -95
- package/src/client/form.js +192 -192
- package/src/client/index.js +45 -45
- package/src/client/registry.js +305 -305
- package/src/client/safe-image.js +91 -91
- package/src/client/shared-cookie.js +225 -225
- package/src/client/store.js +36 -36
- package/src/client/swap.js +188 -188
- package/src/compile/codegen.js +336 -336
- package/src/compile/compile-all.js +149 -149
- package/src/compile/errors.js +66 -66
- package/src/compile/expr.js +409 -409
- package/src/compile/index.js +17 -17
- package/src/compile/parse.js +541 -541
- package/src/compile/resolve.js +211 -211
- package/src/compile/scan-exports.js +51 -51
- package/src/config/defaults.js +541 -534
- package/src/config/index.js +1500 -1469
- package/src/config/pattern.js +107 -107
- package/src/generate.mjs +163 -163
- package/src/http/control-flow.js +71 -71
- package/src/http/cookies-entry.js +21 -21
- package/src/http/cookies.js +277 -277
- package/src/http/request-cache.js +46 -46
- package/src/http/request-context.js +165 -165
- package/src/http/shared-cookie.js +178 -178
- package/src/index.js +101 -101
- package/src/init.mjs +232 -230
- package/src/migrate/apply.mjs +262 -262
- package/src/migrate/babel.mjs +79 -79
- package/src/migrate/classify.mjs +155 -155
- package/src/migrate/config.mjs +126 -126
- package/src/migrate/fs-walk.mjs +191 -191
- package/src/migrate/parse.mjs +26 -26
- package/src/migrate/scan.mjs +177 -177
- package/src/migrate/transform/expr-source.mjs +168 -168
- package/src/migrate/transform/island.mjs +67 -67
- package/src/migrate/transform/jsx-to-component.mjs +302 -302
- package/src/migrate/transform/jsx-to-jsk.mjs +330 -330
- package/src/migrate/transform/page-split.mjs +435 -435
- package/src/migrate/write.mjs +81 -81
- package/src/migrate.mjs +171 -171
- package/src/runtime/alias-hooks.mjs +119 -119
- package/src/runtime/register.mjs +4 -4
- package/src/server/admin/actions.js +229 -229
- package/src/server/admin/auth.js +125 -125
- package/src/server/admin/event-log.js +151 -151
- package/src/server/admin/gate.js +209 -209
- package/src/server/admin/inventory.js +188 -188
- package/src/server/admin/mount.js +56 -56
- package/src/server/admin/router.js +216 -216
- package/src/server/admin/snapshot.js +241 -241
- package/src/server/assets.js +147 -147
- package/src/server/auth/handoff.js +309 -309
- package/src/server/cache-blob.js +70 -70
- package/src/server/cache-control.js +45 -0
- package/src/server/cache-deps.js +42 -42
- package/src/server/cache-vary.js +113 -113
- package/src/server/cloudflare.js +607 -607
- package/src/server/create-app.js +366 -366
- package/src/server/data-cache.js +553 -553
- package/src/server/dev/report.js +485 -485
- package/src/server/dev/socket.js +170 -170
- package/src/server/dev/version-check.mjs +139 -139
- package/src/server/disk-cache.js +233 -233
- package/src/server/ejs-adapter.js +59 -59
- package/src/server/html-cache.js +1196 -1196
- package/src/server/image-optimizer.js +500 -500
- package/src/server/logs/access-middleware.js +66 -66
- package/src/server/logs/file-sink.js +193 -193
- package/src/server/logs/pipeline.js +165 -165
- package/src/server/logs/s3-put.js +214 -214
- package/src/server/logs/s3-sink.js +112 -112
- package/src/server/metadata.js +102 -102
- package/src/server/middleware/compression.js +205 -205
- package/src/server/middleware/csrf.js +134 -134
- package/src/server/middleware/dev-gate.js +75 -75
- package/src/server/middleware/headers.js +37 -37
- package/src/server/middleware/redirects.js +32 -32
- package/src/server/middleware/robots-txt.js +341 -341
- package/src/server/middleware/static-precompressed.js +121 -121
- package/src/server/middleware/trailing-slash.js +53 -53
- package/src/server/middleware/upstream-proxy.js +141 -141
- package/src/server/og-image.js +369 -356
- package/src/server/port-guard.js +255 -255
- package/src/server/prewarm.js +1082 -1082
- package/src/server/redis.js +588 -588
- package/src/server/render.js +910 -910
- package/src/server/router.js +157 -157
- package/src/server/status-page.js +265 -265
- package/src/server/upstream-limiter.js +376 -376
- package/src/server/upstream-tracking.js +166 -166
- package/src/shared/cookie-domain.js +66 -66
- package/src/start.mjs +22 -22
- package/src/templates/layout.ejs +30 -30
- package/src/templates/layout.jsk +30 -30
- package/src/version.mjs +31 -31
- package/src/views/components/loader.js +101 -101
- package/src/views/helpers/html.js +102 -102
- package/src/views/helpers/tags.js +375 -375
- package/types/config/defaults.d.ts +6 -0
- package/types/config/index.d.ts +6 -0
- package/types/server/cache-control.d.ts +28 -0
- package/types/server/og-image.d.ts +5 -0
|
@@ -1,149 +1,149 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tüm `.jsk` dosyalarını derleyip `.jskelet/templates/` altına yazar.
|
|
3
|
-
*/
|
|
4
|
-
import fs from "node:fs";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import { parseTemplate } from "./parse.js";
|
|
7
|
-
import { codegen, normalizeIncludeId } from "./codegen.js";
|
|
8
|
-
import { CompileError } from "./errors.js";
|
|
9
|
-
import {
|
|
10
|
-
collectKnownComponents,
|
|
11
|
-
componentNameFromViewId,
|
|
12
|
-
discoverJskFiles,
|
|
13
|
-
getComponentDirs,
|
|
14
|
-
getViewRoots,
|
|
15
|
-
} from "./resolve.js";
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @param {{ root: string, dirs: Record<string, string> }} config
|
|
19
|
-
* @param {{ quiet?: boolean }} [options]
|
|
20
|
-
* @returns {Promise<{ count: number, manifest: Record<string, string>, outDir: string }>}
|
|
21
|
-
*/
|
|
22
|
-
export async function compileAll(config, _options = {}) {
|
|
23
|
-
const outDir = path.join(config.dirs.generated, "templates");
|
|
24
|
-
const viewRoots = getViewRoots(config);
|
|
25
|
-
const jskFiles = discoverJskFiles(viewRoots);
|
|
26
|
-
const componentDirs = getComponentDirs(config);
|
|
27
|
-
const knownComponents = collectKnownComponents(componentDirs, jskFiles);
|
|
28
|
-
|
|
29
|
-
// Önceki çıktıyı temizle — silinmiş şablonlar kalmasın.
|
|
30
|
-
fs.rmSync(outDir, { recursive: true, force: true });
|
|
31
|
-
fs.mkdirSync(outDir, { recursive: true });
|
|
32
|
-
|
|
33
|
-
/** @type {Record<string, string>} */
|
|
34
|
-
const manifest = {};
|
|
35
|
-
/** @type {Map<string, { code: string, includes: string[], includeEntries: { id: string, index: number }[], source: string, relative: string }>} */
|
|
36
|
-
const compiled = new Map();
|
|
37
|
-
|
|
38
|
-
for (const [viewId, file] of jskFiles) {
|
|
39
|
-
const source = fs.readFileSync(file, "utf8");
|
|
40
|
-
const relative = path.relative(config.root, file).split(path.sep).join("/");
|
|
41
|
-
|
|
42
|
-
let ast;
|
|
43
|
-
try {
|
|
44
|
-
ast = parseTemplate(source, { file: relative });
|
|
45
|
-
} catch (error) {
|
|
46
|
-
if (error instanceof CompileError) throw error;
|
|
47
|
-
throw error;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const { code, includes, includeEntries } = codegen(ast, {
|
|
51
|
-
viewId,
|
|
52
|
-
file: relative,
|
|
53
|
-
knownComponents,
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
compiled.set(viewId, { code, includes, includeEntries, source, relative });
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Include hedefleri mevcut mu?
|
|
60
|
-
for (const [, { includeEntries, source, relative }] of compiled) {
|
|
61
|
-
for (const { id, index } of includeEntries) {
|
|
62
|
-
const normalized = normalizeIncludeId(id);
|
|
63
|
-
if (!compiled.has(normalized) && !jskFiles.has(normalized)) {
|
|
64
|
-
throw new CompileError(`Unknown include "${id}"`, {
|
|
65
|
-
file: relative,
|
|
66
|
-
source,
|
|
67
|
-
index,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
for (const [viewId, { code }] of compiled) {
|
|
74
|
-
const outFile = path.join(outDir, `${viewId}.mjs`);
|
|
75
|
-
fs.mkdirSync(path.dirname(outFile), { recursive: true });
|
|
76
|
-
fs.writeFileSync(outFile, code, "utf8");
|
|
77
|
-
manifest[viewId] = `${viewId}.mjs`.split(path.sep).join("/");
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const manifestPath = path.join(outDir, "manifest.json");
|
|
81
|
-
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
|
|
82
|
-
|
|
83
|
-
// Bileşen adı → view id haritası (runtime kayıt için)
|
|
84
|
-
/** @type {Record<string, string>} */
|
|
85
|
-
const components = {};
|
|
86
|
-
for (const viewId of Object.keys(manifest)) {
|
|
87
|
-
const name = componentNameFromViewId(viewId);
|
|
88
|
-
if (name) components[name] = viewId;
|
|
89
|
-
}
|
|
90
|
-
fs.writeFileSync(
|
|
91
|
-
path.join(outDir, "components.json"),
|
|
92
|
-
`${JSON.stringify(components, null, 2)}\n`,
|
|
93
|
-
"utf8",
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
return { count: compiled.size, manifest, outDir };
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Manifest yoksa veya herhangi bir `.jsk` daha yeniyse yeniden derler.
|
|
101
|
-
* Dev sunucu restart'ında build watch kaçırmış olsa bile şablonlar güncel kalır.
|
|
102
|
-
*
|
|
103
|
-
* @param {{ root: string, dirs: Record<string, string> }} config
|
|
104
|
-
* @returns {Promise<{ count: number, rebuilt: boolean }>}
|
|
105
|
-
*/
|
|
106
|
-
export async function ensureTemplatesCompiled(config) {
|
|
107
|
-
const viewRoots = getViewRoots(config);
|
|
108
|
-
const jskFiles = discoverJskFiles(viewRoots);
|
|
109
|
-
if (jskFiles.size === 0) {
|
|
110
|
-
return { count: 0, rebuilt: false };
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const outDir = path.join(config.dirs.generated, "templates");
|
|
114
|
-
const manifestPath = path.join(outDir, "manifest.json");
|
|
115
|
-
let needs = !fs.existsSync(manifestPath);
|
|
116
|
-
|
|
117
|
-
if (!needs) {
|
|
118
|
-
const manifestMtime = fs.statSync(manifestPath).mtimeMs;
|
|
119
|
-
for (const file of jskFiles.values()) {
|
|
120
|
-
if (fs.statSync(file).mtimeMs > manifestMtime) {
|
|
121
|
-
needs = true;
|
|
122
|
-
break;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (!needs) {
|
|
128
|
-
return { count: jskFiles.size, rebuilt: false };
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const result = await compileAll(config, { quiet: true });
|
|
132
|
-
return { count: result.count, rebuilt: true };
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Tek kaynak dizgisini derler (birim testleri).
|
|
137
|
-
* @param {string} source
|
|
138
|
-
* @param {{ viewId?: string, file?: string, knownComponents?: Set<string> }} [options]
|
|
139
|
-
* @returns {{ code: string, includes: string[], components: string[] }}
|
|
140
|
-
*/
|
|
141
|
-
export function compileSource(source, options = {}) {
|
|
142
|
-
const viewId = options.viewId ?? "test";
|
|
143
|
-
const ast = parseTemplate(source, { file: options.file ?? "test.jsk" });
|
|
144
|
-
return codegen(ast, {
|
|
145
|
-
viewId,
|
|
146
|
-
file: options.file ?? "test.jsk",
|
|
147
|
-
knownComponents: options.knownComponents ?? null,
|
|
148
|
-
});
|
|
149
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Tüm `.jsk` dosyalarını derleyip `.jskelet/templates/` altına yazar.
|
|
3
|
+
*/
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { parseTemplate } from "./parse.js";
|
|
7
|
+
import { codegen, normalizeIncludeId } from "./codegen.js";
|
|
8
|
+
import { CompileError } from "./errors.js";
|
|
9
|
+
import {
|
|
10
|
+
collectKnownComponents,
|
|
11
|
+
componentNameFromViewId,
|
|
12
|
+
discoverJskFiles,
|
|
13
|
+
getComponentDirs,
|
|
14
|
+
getViewRoots,
|
|
15
|
+
} from "./resolve.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {{ root: string, dirs: Record<string, string> }} config
|
|
19
|
+
* @param {{ quiet?: boolean }} [options]
|
|
20
|
+
* @returns {Promise<{ count: number, manifest: Record<string, string>, outDir: string }>}
|
|
21
|
+
*/
|
|
22
|
+
export async function compileAll(config, _options = {}) {
|
|
23
|
+
const outDir = path.join(config.dirs.generated, "templates");
|
|
24
|
+
const viewRoots = getViewRoots(config);
|
|
25
|
+
const jskFiles = discoverJskFiles(viewRoots);
|
|
26
|
+
const componentDirs = getComponentDirs(config);
|
|
27
|
+
const knownComponents = collectKnownComponents(componentDirs, jskFiles);
|
|
28
|
+
|
|
29
|
+
// Önceki çıktıyı temizle — silinmiş şablonlar kalmasın.
|
|
30
|
+
fs.rmSync(outDir, { recursive: true, force: true });
|
|
31
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
32
|
+
|
|
33
|
+
/** @type {Record<string, string>} */
|
|
34
|
+
const manifest = {};
|
|
35
|
+
/** @type {Map<string, { code: string, includes: string[], includeEntries: { id: string, index: number }[], source: string, relative: string }>} */
|
|
36
|
+
const compiled = new Map();
|
|
37
|
+
|
|
38
|
+
for (const [viewId, file] of jskFiles) {
|
|
39
|
+
const source = fs.readFileSync(file, "utf8");
|
|
40
|
+
const relative = path.relative(config.root, file).split(path.sep).join("/");
|
|
41
|
+
|
|
42
|
+
let ast;
|
|
43
|
+
try {
|
|
44
|
+
ast = parseTemplate(source, { file: relative });
|
|
45
|
+
} catch (error) {
|
|
46
|
+
if (error instanceof CompileError) throw error;
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const { code, includes, includeEntries } = codegen(ast, {
|
|
51
|
+
viewId,
|
|
52
|
+
file: relative,
|
|
53
|
+
knownComponents,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
compiled.set(viewId, { code, includes, includeEntries, source, relative });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Include hedefleri mevcut mu?
|
|
60
|
+
for (const [, { includeEntries, source, relative }] of compiled) {
|
|
61
|
+
for (const { id, index } of includeEntries) {
|
|
62
|
+
const normalized = normalizeIncludeId(id);
|
|
63
|
+
if (!compiled.has(normalized) && !jskFiles.has(normalized)) {
|
|
64
|
+
throw new CompileError(`Unknown include "${id}"`, {
|
|
65
|
+
file: relative,
|
|
66
|
+
source,
|
|
67
|
+
index,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for (const [viewId, { code }] of compiled) {
|
|
74
|
+
const outFile = path.join(outDir, `${viewId}.mjs`);
|
|
75
|
+
fs.mkdirSync(path.dirname(outFile), { recursive: true });
|
|
76
|
+
fs.writeFileSync(outFile, code, "utf8");
|
|
77
|
+
manifest[viewId] = `${viewId}.mjs`.split(path.sep).join("/");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const manifestPath = path.join(outDir, "manifest.json");
|
|
81
|
+
fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
|
|
82
|
+
|
|
83
|
+
// Bileşen adı → view id haritası (runtime kayıt için)
|
|
84
|
+
/** @type {Record<string, string>} */
|
|
85
|
+
const components = {};
|
|
86
|
+
for (const viewId of Object.keys(manifest)) {
|
|
87
|
+
const name = componentNameFromViewId(viewId);
|
|
88
|
+
if (name) components[name] = viewId;
|
|
89
|
+
}
|
|
90
|
+
fs.writeFileSync(
|
|
91
|
+
path.join(outDir, "components.json"),
|
|
92
|
+
`${JSON.stringify(components, null, 2)}\n`,
|
|
93
|
+
"utf8",
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
return { count: compiled.size, manifest, outDir };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Manifest yoksa veya herhangi bir `.jsk` daha yeniyse yeniden derler.
|
|
101
|
+
* Dev sunucu restart'ında build watch kaçırmış olsa bile şablonlar güncel kalır.
|
|
102
|
+
*
|
|
103
|
+
* @param {{ root: string, dirs: Record<string, string> }} config
|
|
104
|
+
* @returns {Promise<{ count: number, rebuilt: boolean }>}
|
|
105
|
+
*/
|
|
106
|
+
export async function ensureTemplatesCompiled(config) {
|
|
107
|
+
const viewRoots = getViewRoots(config);
|
|
108
|
+
const jskFiles = discoverJskFiles(viewRoots);
|
|
109
|
+
if (jskFiles.size === 0) {
|
|
110
|
+
return { count: 0, rebuilt: false };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const outDir = path.join(config.dirs.generated, "templates");
|
|
114
|
+
const manifestPath = path.join(outDir, "manifest.json");
|
|
115
|
+
let needs = !fs.existsSync(manifestPath);
|
|
116
|
+
|
|
117
|
+
if (!needs) {
|
|
118
|
+
const manifestMtime = fs.statSync(manifestPath).mtimeMs;
|
|
119
|
+
for (const file of jskFiles.values()) {
|
|
120
|
+
if (fs.statSync(file).mtimeMs > manifestMtime) {
|
|
121
|
+
needs = true;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!needs) {
|
|
128
|
+
return { count: jskFiles.size, rebuilt: false };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const result = await compileAll(config, { quiet: true });
|
|
132
|
+
return { count: result.count, rebuilt: true };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Tek kaynak dizgisini derler (birim testleri).
|
|
137
|
+
* @param {string} source
|
|
138
|
+
* @param {{ viewId?: string, file?: string, knownComponents?: Set<string> }} [options]
|
|
139
|
+
* @returns {{ code: string, includes: string[], components: string[] }}
|
|
140
|
+
*/
|
|
141
|
+
export function compileSource(source, options = {}) {
|
|
142
|
+
const viewId = options.viewId ?? "test";
|
|
143
|
+
const ast = parseTemplate(source, { file: options.file ?? "test.jsk" });
|
|
144
|
+
return codegen(ast, {
|
|
145
|
+
viewId,
|
|
146
|
+
file: options.file ?? "test.jsk",
|
|
147
|
+
knownComponents: options.knownComponents ?? null,
|
|
148
|
+
});
|
|
149
|
+
}
|
package/src/compile/errors.js
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Şablon derleme hataları. Satır/sütun korunur ki DX overlay ve CLI
|
|
3
|
-
* çıktısı kaynağa işaret edebilsin.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @param {string} source
|
|
8
|
-
* @param {number} index
|
|
9
|
-
* @returns {{ line: number, column: number }}
|
|
10
|
-
*/
|
|
11
|
-
export function indexToLocation(source, index) {
|
|
12
|
-
let line = 1;
|
|
13
|
-
let column = 1;
|
|
14
|
-
const end = Math.min(index, source.length);
|
|
15
|
-
for (let i = 0; i < end; i++) {
|
|
16
|
-
if (source[i] === "\n") {
|
|
17
|
-
line += 1;
|
|
18
|
-
column = 1;
|
|
19
|
-
} else {
|
|
20
|
-
column += 1;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return { line, column };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* @param {string} source
|
|
28
|
-
* @param {number} line
|
|
29
|
-
* @returns {string}
|
|
30
|
-
*/
|
|
31
|
-
function lineSnippet(source, line) {
|
|
32
|
-
const lines = source.split(/\r?\n/);
|
|
33
|
-
return lines[line - 1] ?? "";
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export class CompileError extends Error {
|
|
37
|
-
/**
|
|
38
|
-
* @param {string} message
|
|
39
|
-
* @param {{ file?: string, source?: string, index?: number,
|
|
40
|
-
* line?: number, column?: number }} [opts]
|
|
41
|
-
*/
|
|
42
|
-
constructor(message, opts = {}) {
|
|
43
|
-
let line = opts.line;
|
|
44
|
-
let column = opts.column;
|
|
45
|
-
if ((line == null || column == null) && opts.source != null && opts.index != null) {
|
|
46
|
-
const loc = indexToLocation(opts.source, opts.index);
|
|
47
|
-
line = loc.line;
|
|
48
|
-
column = loc.column;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const where =
|
|
52
|
-
opts.file && line != null
|
|
53
|
-
? `${opts.file}:${line}:${column ?? 1}`
|
|
54
|
-
: opts.file ?? "";
|
|
55
|
-
const snippet =
|
|
56
|
-
opts.source && line != null ? lineSnippet(opts.source, line).trimEnd() : "";
|
|
57
|
-
const head = where ? `${where}\n` : "";
|
|
58
|
-
const body = snippet ? `${message}\n\n ${snippet}\n ${" ".repeat((column ?? 1) - 1)}^` : message;
|
|
59
|
-
|
|
60
|
-
super(`${head}${body}`);
|
|
61
|
-
this.name = "CompileError";
|
|
62
|
-
this.file = opts.file;
|
|
63
|
-
this.line = line;
|
|
64
|
-
this.column = column;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Şablon derleme hataları. Satır/sütun korunur ki DX overlay ve CLI
|
|
3
|
+
* çıktısı kaynağa işaret edebilsin.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {string} source
|
|
8
|
+
* @param {number} index
|
|
9
|
+
* @returns {{ line: number, column: number }}
|
|
10
|
+
*/
|
|
11
|
+
export function indexToLocation(source, index) {
|
|
12
|
+
let line = 1;
|
|
13
|
+
let column = 1;
|
|
14
|
+
const end = Math.min(index, source.length);
|
|
15
|
+
for (let i = 0; i < end; i++) {
|
|
16
|
+
if (source[i] === "\n") {
|
|
17
|
+
line += 1;
|
|
18
|
+
column = 1;
|
|
19
|
+
} else {
|
|
20
|
+
column += 1;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return { line, column };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {string} source
|
|
28
|
+
* @param {number} line
|
|
29
|
+
* @returns {string}
|
|
30
|
+
*/
|
|
31
|
+
function lineSnippet(source, line) {
|
|
32
|
+
const lines = source.split(/\r?\n/);
|
|
33
|
+
return lines[line - 1] ?? "";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class CompileError extends Error {
|
|
37
|
+
/**
|
|
38
|
+
* @param {string} message
|
|
39
|
+
* @param {{ file?: string, source?: string, index?: number,
|
|
40
|
+
* line?: number, column?: number }} [opts]
|
|
41
|
+
*/
|
|
42
|
+
constructor(message, opts = {}) {
|
|
43
|
+
let line = opts.line;
|
|
44
|
+
let column = opts.column;
|
|
45
|
+
if ((line == null || column == null) && opts.source != null && opts.index != null) {
|
|
46
|
+
const loc = indexToLocation(opts.source, opts.index);
|
|
47
|
+
line = loc.line;
|
|
48
|
+
column = loc.column;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const where =
|
|
52
|
+
opts.file && line != null
|
|
53
|
+
? `${opts.file}:${line}:${column ?? 1}`
|
|
54
|
+
: opts.file ?? "";
|
|
55
|
+
const snippet =
|
|
56
|
+
opts.source && line != null ? lineSnippet(opts.source, line).trimEnd() : "";
|
|
57
|
+
const head = where ? `${where}\n` : "";
|
|
58
|
+
const body = snippet ? `${message}\n\n ${snippet}\n ${" ".repeat((column ?? 1) - 1)}^` : message;
|
|
59
|
+
|
|
60
|
+
super(`${head}${body}`);
|
|
61
|
+
this.name = "CompileError";
|
|
62
|
+
this.file = opts.file;
|
|
63
|
+
this.line = line;
|
|
64
|
+
this.column = column;
|
|
65
|
+
}
|
|
66
|
+
}
|