@rafters/veneer 0.0.0-stage → 0.0.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.
@@ -0,0 +1,1024 @@
1
+ import { createRequire } from "node:module";
2
+ import path from "node:path";
3
+ import { readFile, readdir, stat } from "node:fs/promises";
4
+ import { existsSync, realpathSync } from "node:fs";
5
+ import { format } from "node:util";
6
+ import { AstroCheck } from "@astrojs/language-server";
7
+ //#region src/config.ts
8
+ const CONFIG_FILE = ".rafters/config.rafters.json";
9
+ function isObject(value) {
10
+ return typeof value === "object" && value !== null && !Array.isArray(value);
11
+ }
12
+ function fieldError(field, problem, ...value) {
13
+ const error = {
14
+ code: "config-field",
15
+ message: `${field}: ${problem}`,
16
+ field
17
+ };
18
+ if (value.length > 0) error.value = value[0];
19
+ return error;
20
+ }
21
+ function errnoOf(error) {
22
+ return error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : void 0;
23
+ }
24
+ function messageOf(error) {
25
+ return error instanceof Error ? error.message : String(error);
26
+ }
27
+ async function readConfigObject(root) {
28
+ const unreadable = (problem) => ({ error: {
29
+ code: "config-unreadable",
30
+ message: `${CONFIG_FILE}: ${problem}`
31
+ } });
32
+ let bytes;
33
+ try {
34
+ bytes = await readFile(path.join(root, CONFIG_FILE));
35
+ } catch (error) {
36
+ const errno = errnoOf(error);
37
+ if (errno === "ENOENT" || errno === "ENOTDIR") return { error: {
38
+ code: "config-missing",
39
+ message: `${CONFIG_FILE} not found`
40
+ } };
41
+ return unreadable(messageOf(error));
42
+ }
43
+ try {
44
+ const parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
45
+ return isObject(parsed) ? { config: parsed } : unreadable("the text is not a JSON object");
46
+ } catch (error) {
47
+ return unreadable(messageOf(error));
48
+ }
49
+ }
50
+ function entryPath(entry) {
51
+ if (typeof entry === "string") return entry;
52
+ if (!isObject(entry) || typeof entry.path !== "string") return void 0;
53
+ return !("root" in entry) || entry.root === true ? entry.path : void 0;
54
+ }
55
+ async function checkEntryPath(root, entry) {
56
+ if (entry === "") return "the path is empty";
57
+ if (path.isAbsolute(entry)) return "the path is absolute";
58
+ const fromRoot = path.relative(root, path.resolve(root, entry));
59
+ if (fromRoot === ".." || fromRoot.startsWith(`..${path.sep}`) || path.isAbsolute(fromRoot)) return "the path is outside the project root";
60
+ try {
61
+ return (await stat(path.resolve(root, entry))).isDirectory() || "the path is not a folder";
62
+ } catch (error) {
63
+ const errno = errnoOf(error);
64
+ if (errno === "ENOENT" || errno === "ENOTDIR") return false;
65
+ throw error;
66
+ }
67
+ }
68
+ async function readConfig(root) {
69
+ const read = await readConfigObject(root);
70
+ if ("error" in read) return {
71
+ ok: false,
72
+ errors: [read.error]
73
+ };
74
+ const { config } = read;
75
+ const errors = [];
76
+ const componentFolders = [];
77
+ const notices = [];
78
+ const { componentsPath, intent, veneer } = config;
79
+ if (componentsPath === void 0) errors.push(fieldError("componentsPath", "the field is missing"));
80
+ else if (typeof componentsPath !== "string" && !(Array.isArray(componentsPath) && componentsPath.length > 0)) errors.push(fieldError("componentsPath", "expected a string or a non-empty list", componentsPath));
81
+ else {
82
+ const entries = Array.isArray(componentsPath) ? componentsPath : [componentsPath];
83
+ for (const [index, entry] of entries.entries()) {
84
+ const field = Array.isArray(componentsPath) ? `componentsPath[${index}]` : "componentsPath";
85
+ const written = entryPath(entry);
86
+ if (written === void 0) {
87
+ errors.push(fieldError(field, "expected a string or { path, root: true }", entry));
88
+ continue;
89
+ }
90
+ const checked = await checkEntryPath(root, written);
91
+ if (typeof checked === "string") errors.push(fieldError(field, checked, entry));
92
+ else if (checked) componentFolders.push(written);
93
+ else notices.push({
94
+ code: "components-folder-missing",
95
+ message: `${written} named by componentsPath does not exist`
96
+ });
97
+ }
98
+ }
99
+ if (intent !== void 0 && typeof intent !== "string") errors.push(fieldError("intent", "expected a string", intent));
100
+ if (veneer !== void 0 && !isObject(veneer)) errors.push(fieldError("veneer", "expected an object", veneer));
101
+ else if (veneer?.mdxPath !== void 0 && typeof veneer.mdxPath !== "string") errors.push(fieldError("veneer.mdxPath", "expected a string", veneer.mdxPath));
102
+ if (errors.length > 0) return {
103
+ ok: false,
104
+ errors
105
+ };
106
+ return {
107
+ ok: true,
108
+ intent: typeof intent === "string" ? intent : null,
109
+ componentFolders,
110
+ notices
111
+ };
112
+ }
113
+ //#endregion
114
+ //#region src/read.ts
115
+ const NO_ASTRO_LINE = "seems to be an Astro project, but we couldn't find Astro or Astro is not installed";
116
+ const NO_INTEGRATION_LINE = "Couldn't find package @astrojs/";
117
+ const SEVERITIES = {
118
+ 1: "error",
119
+ 2: "warning",
120
+ 3: "info",
121
+ 4: "hint"
122
+ };
123
+ const require$1 = createRequire(import.meta.url);
124
+ const typescriptPath = require$1.resolve("typescript");
125
+ const ts = require$1(typescriptPath);
126
+ var ProjectError = class extends Error {
127
+ code;
128
+ constructor(code, message) {
129
+ super(message);
130
+ this.name = "ProjectError";
131
+ this.code = code;
132
+ }
133
+ };
134
+ let aProjectIsOpen = false;
135
+ let serverIsPrepared = false;
136
+ let constructedContext;
137
+ let unsavedChanges = 0;
138
+ const capturePlugin = {
139
+ name: "veneer-capture-context",
140
+ capabilities: {},
141
+ create(context) {
142
+ constructedContext ??= context;
143
+ return {};
144
+ }
145
+ };
146
+ function prepareLanguageServer() {
147
+ if (serverIsPrepared) return;
148
+ serverIsPrepared = true;
149
+ const serverRequire = createRequire(require$1.resolve("@astrojs/language-server/package.json"));
150
+ const { setIsTrusted } = serverRequire("./dist/importPackage.js");
151
+ setIsTrusted(false);
152
+ const kit = serverRequire("@volar/kit/lib/createChecker.js");
153
+ const original = kit.createTypeScriptChecker;
154
+ kit.createTypeScriptChecker = (languages, services, ...rest) => original(languages, [...services, capturePlugin], ...rest);
155
+ }
156
+ function constructAstroCheck(root) {
157
+ const consoleError = console.error;
158
+ console.error = (...args) => {
159
+ if (!format(...args).endsWith(NO_ASTRO_LINE)) consoleError(...args);
160
+ };
161
+ try {
162
+ return new AstroCheck(root, typescriptPath, void 0);
163
+ } finally {
164
+ console.error = consoleError;
165
+ }
166
+ }
167
+ function holdingOnly(file) {
168
+ return (directory) => {
169
+ const prefix = directory.endsWith("/") ? directory : `${directory}/`;
170
+ if (!file.startsWith(prefix)) return {
171
+ files: [],
172
+ directories: []
173
+ };
174
+ const [next = "", ...below] = file.slice(prefix.length).split("/");
175
+ return below.length === 0 ? {
176
+ files: [next],
177
+ directories: []
178
+ } : {
179
+ files: [],
180
+ directories: [next]
181
+ };
182
+ };
183
+ }
184
+ function overlaySys(unsaved) {
185
+ const { sys } = ts;
186
+ const { readFile, getModifiedTime, fileExists, readDirectory } = sys;
187
+ sys.readFile = (file, encoding) => unsaved.get(file)?.text ?? readFile.call(sys, file, encoding);
188
+ sys.getModifiedTime = (file) => unsaved.get(file)?.modified ?? getModifiedTime?.call(sys, file);
189
+ sys.fileExists = (file) => unsaved.has(file) || fileExists.call(sys, file);
190
+ sys.readDirectory = (directory, extensions, excludes, includes, depth) => {
191
+ const found = readDirectory.call(sys, directory, extensions, excludes, includes, depth);
192
+ const taken = [...unsaved.keys()].filter((file) => !found.includes(file) && ts.matchFiles(directory, extensions, excludes, includes, sys.useCaseSensitiveFileNames, sys.getCurrentDirectory(), depth, holdingOnly(file), (name) => name).length > 0);
193
+ return [...found, ...taken];
194
+ };
195
+ return () => {
196
+ sys.readFile = readFile;
197
+ sys.getModifiedTime = getModifiedTime;
198
+ sys.fileExists = fileExists;
199
+ sys.readDirectory = readDirectory;
200
+ };
201
+ }
202
+ function programOf(context) {
203
+ const program = context?.inject("typescript/languageService")?.getProgram();
204
+ if (!program) throw new Error("the language service holds no program");
205
+ return program;
206
+ }
207
+ function toDiagnostic(file, diagnostic) {
208
+ const { range, severity, source, code, message } = diagnostic;
209
+ return {
210
+ file,
211
+ line: range.start.line + 1,
212
+ column: range.start.character + 1,
213
+ endLine: range.end.line + 1,
214
+ endColumn: range.end.character + 1,
215
+ severity: SEVERITIES[severity ?? 1],
216
+ code: `${source ?? ""}(${code ?? ""})`,
217
+ message
218
+ };
219
+ }
220
+ function isProjectRelative(file) {
221
+ return !path.isAbsolute(file) && !file.includes("\\") && file === path.posix.normalize(file) && !file.startsWith("../");
222
+ }
223
+ function badPath(file) {
224
+ return new ProjectError("bad-path", `${file} is not a project-relative path with / separators`);
225
+ }
226
+ function unsavedEntry(text) {
227
+ unsavedChanges += 1;
228
+ return {
229
+ text,
230
+ modified: new Date(-unsavedChanges)
231
+ };
232
+ }
233
+ async function openProject(projectRoot, options = {}) {
234
+ if (aProjectIsOpen) throw new ProjectError("already-open", "a veneer project is already open in this process");
235
+ const root = path.resolve(projectRoot);
236
+ if (!existsSync(path.join(root, "tsconfig.json"))) throw new ProjectError("tsconfig-missing", `tsconfig.json not found at ${root}`);
237
+ const unsaved = /* @__PURE__ */ new Map();
238
+ for (const [file, text] of Object.entries(options.unsaved ?? {})) {
239
+ if (!isProjectRelative(file)) throw badPath(file);
240
+ unsaved.set(path.join(root, file), unsavedEntry(text));
241
+ }
242
+ aProjectIsOpen = true;
243
+ const consoleInfo = console.info;
244
+ console.info = (...args) => {
245
+ if (!format(...args).startsWith(NO_INTEGRATION_LINE)) consoleInfo(...args);
246
+ };
247
+ const restoreSys = overlaySys(unsaved);
248
+ try {
249
+ prepareLanguageServer();
250
+ constructedContext = void 0;
251
+ const astroCheck = constructAstroCheck(root);
252
+ let context = constructedContext;
253
+ constructedContext = void 0;
254
+ const fileNames = astroCheck.linter.getRootFileNames().slice(0, 1);
255
+ await astroCheck.lint({ fileNames });
256
+ let program = programOf(context);
257
+ let closed = false;
258
+ const rootFile = (file) => {
259
+ if (closed) throw new ProjectError("closed", "the veneer project is closed");
260
+ if (!isProjectRelative(file)) throw badPath(file);
261
+ const absolute = path.join(root, file);
262
+ if (!astroCheck.linter.getRootFileNames().includes(absolute)) throw new ProjectError("not-root-file", `${file} is not a root file of the program`);
263
+ return absolute;
264
+ };
265
+ return {
266
+ ts,
267
+ checker: astroCheck.linter,
268
+ root,
269
+ program() {
270
+ if (closed) throw new ProjectError("closed", "the veneer project is closed");
271
+ return program;
272
+ },
273
+ async diagnostics(file) {
274
+ const absolute = rootFile(file);
275
+ const { fileResult } = await astroCheck.lint({ fileNames: [absolute] });
276
+ program = programOf(context);
277
+ return fileResult.flatMap(({ errors }) => errors.map((d) => toDiagnostic(file, d)));
278
+ },
279
+ setUnsaved(file, text) {
280
+ const absolute = rootFile(file);
281
+ unsaved.set(absolute, unsavedEntry(text));
282
+ astroCheck.linter.fileUpdated(absolute);
283
+ },
284
+ clearUnsaved(file) {
285
+ const absolute = rootFile(file);
286
+ unsaved.delete(absolute);
287
+ astroCheck.linter.fileUpdated(absolute);
288
+ },
289
+ close() {
290
+ if (closed) throw new ProjectError("closed", "the veneer project is closed");
291
+ closed = true;
292
+ unsaved.clear();
293
+ restoreSys();
294
+ context = void 0;
295
+ aProjectIsOpen = false;
296
+ }
297
+ };
298
+ } catch (error) {
299
+ restoreSys();
300
+ aProjectIsOpen = false;
301
+ throw error;
302
+ } finally {
303
+ console.info = consoleInfo;
304
+ }
305
+ }
306
+ //#endregion
307
+ //#region src/resolve.ts
308
+ const require = createRequire(import.meta.url);
309
+ const { URI } = createRequire(require.resolve("@astrojs/language-server/package.json"))("vscode-uri");
310
+ function compareCodePoints(a, b) {
311
+ const left = [...a];
312
+ const right = [...b];
313
+ for (let i = 0; i < Math.min(left.length, right.length); i += 1) {
314
+ const difference = (left[i]?.codePointAt(0) ?? 0) - (right[i]?.codePointAt(0) ?? 0);
315
+ if (difference !== 0) return difference;
316
+ }
317
+ return left.length - right.length;
318
+ }
319
+ const posix = (file) => file.split(path.sep).join("/");
320
+ const relativeFile = (root, file) => posix(path.relative(root, file));
321
+ const inNodeModules = (declaration) => declaration.getSourceFile().fileName.includes("/node_modules/");
322
+ async function walkFolder(folder, into) {
323
+ const entries = await readdir(folder, { withFileTypes: true });
324
+ for (const entry of entries) {
325
+ const entryPath = path.join(folder, entry.name);
326
+ let isFolder = entry.isDirectory();
327
+ let isFile = entry.isFile();
328
+ if (entry.isSymbolicLink()) {
329
+ isFile = (await stat(entryPath).catch(() => void 0))?.isFile() ?? false;
330
+ isFolder = false;
331
+ }
332
+ if (isFolder) {
333
+ if (entry.name !== "node_modules" && !entry.name.startsWith(".")) await walkFolder(entryPath, into);
334
+ } else if (isFile && (entry.name.endsWith(".tsx") || entry.name.endsWith(".astro"))) into.add(posix(entryPath));
335
+ }
336
+ }
337
+ function scriptOf(reader, file) {
338
+ return reader.project.checker.language.scripts.get(URI.file(file));
339
+ }
340
+ function sourceOffset(reader, file, offset) {
341
+ const { language } = reader.project.checker;
342
+ const script = scriptOf(reader, file);
343
+ const tsx = script?.generated?.embeddedCodes.get("tsx");
344
+ if (!script || !tsx) return void 0;
345
+ for (const [source] of language.maps.get(tsx, script).toSourceLocation(offset)) return source;
346
+ }
347
+ function generatedOffset(reader, file, offset) {
348
+ const { language } = reader.project.checker;
349
+ const script = scriptOf(reader, file);
350
+ const tsx = script?.generated?.embeddedCodes.get("tsx");
351
+ if (!script || !tsx) return void 0;
352
+ for (const [generated] of language.maps.get(tsx, script).toGeneratedLocation(offset)) return generated;
353
+ }
354
+ function positionOf(reader, sourceFile, offset) {
355
+ const file = sourceFile.fileName;
356
+ let position;
357
+ if (file.endsWith(".astro")) {
358
+ const source = sourceOffset(reader, file, offset);
359
+ const snapshot = scriptOf(reader, file)?.snapshot;
360
+ if (source === void 0 || !snapshot) return void 0;
361
+ const text = snapshot.getText(0, snapshot.getLength());
362
+ position = reader.ts.createSourceMapSource(file, text).getLineAndCharacterOfPosition(source);
363
+ } else position = sourceFile.getLineAndCharacterOfPosition(offset);
364
+ return {
365
+ line: position.line + 1,
366
+ column: position.character + 1
367
+ };
368
+ }
369
+ function collectBindingDefaults(ts, pattern, into) {
370
+ for (const element of pattern.elements) {
371
+ if (element.dotDotDotToken || !element.initializer) continue;
372
+ const key = element.propertyName ?? element.name;
373
+ if (ts.isIdentifier(key) || ts.isStringLiteral(key)) into.set(key.text, element.initializer.getText());
374
+ }
375
+ }
376
+ function renderFunction({ ts, tc }, start) {
377
+ const seen = /* @__PURE__ */ new Set();
378
+ let node = start;
379
+ while (node && !seen.has(node)) {
380
+ seen.add(node);
381
+ if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node)) return node;
382
+ if (ts.isVariableDeclaration(node)) node = node.initializer;
383
+ else if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node)) node = node.expression;
384
+ else if (ts.isCallExpression(node)) node = node.arguments[0];
385
+ else if (ts.isIdentifier(node)) {
386
+ const declaration = tc.getSymbolAtLocation(node)?.valueDeclaration;
387
+ node = declaration && (ts.isVariableDeclaration(declaration) || ts.isFunctionDeclaration(declaration)) ? declaration : void 0;
388
+ } else return void 0;
389
+ }
390
+ }
391
+ function tsxDefaults(reader, declaration) {
392
+ const { ts, tc } = reader;
393
+ const defaults = /* @__PURE__ */ new Map();
394
+ const render = renderFunction(reader, declaration);
395
+ const parameter = render?.parameters[0];
396
+ if (!parameter) return defaults;
397
+ if (ts.isObjectBindingPattern(parameter.name)) {
398
+ collectBindingDefaults(ts, parameter.name, defaults);
399
+ return defaults;
400
+ }
401
+ const { body } = render;
402
+ const parameterSymbol = tc.getSymbolAtLocation(parameter.name);
403
+ if (!body || !parameterSymbol) return defaults;
404
+ const visit = (node) => {
405
+ if (ts.isFunctionLike(node)) return;
406
+ if (ts.isVariableDeclaration(node) && ts.isObjectBindingPattern(node.name) && node.initializer && ts.isIdentifier(node.initializer) && tc.getSymbolAtLocation(node.initializer) === parameterSymbol) collectBindingDefaults(ts, node.name, defaults);
407
+ ts.forEachChild(node, visit);
408
+ };
409
+ ts.forEachChild(body, visit);
410
+ return defaults;
411
+ }
412
+ function withoutAssertions(ts, node) {
413
+ let current = node;
414
+ while (ts.isAsExpression(current) || ts.isSatisfiesExpression(current) || ts.isTypeAssertionExpression(current) || ts.isNonNullExpression(current) || ts.isParenthesizedExpression(current)) current = current.expression;
415
+ return current;
416
+ }
417
+ function astroDefaults(ts, sourceFile) {
418
+ const defaults = /* @__PURE__ */ new Map();
419
+ const visit = (node) => {
420
+ if (ts.isVariableDeclaration(node) && ts.isObjectBindingPattern(node.name) && node.initializer && withoutAssertions(ts, node.initializer).getText() === "Astro.props") collectBindingDefaults(ts, node.name, defaults);
421
+ ts.forEachChild(node, visit);
422
+ };
423
+ visit(sourceFile);
424
+ return defaults;
425
+ }
426
+ function literalValuesOfTypes({ ts }, types) {
427
+ const values = /* @__PURE__ */ new Map();
428
+ for (const type of types) for (const member of type.isUnion() ? type.types : [type]) {
429
+ if (member.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Null | ts.TypeFlags.Never)) continue;
430
+ if (!member.isStringLiteral() && !member.isNumberLiteral()) return void 0;
431
+ values.set(valueKey(member.value), member.value);
432
+ }
433
+ return values.size >= 2 ? [...values.values()] : void 0;
434
+ }
435
+ const valueKey = (value) => `${typeof value}:${value}`;
436
+ var WalkFailed = class extends Error {};
437
+ function resolvedDeclaration({ ts, tc }, name) {
438
+ const symbol = tc.getSymbolAtLocation(name);
439
+ return (symbol && symbol.flags & ts.SymbolFlags.Alias ? tc.getAliasedSymbol(symbol) : symbol)?.declarations?.[0];
440
+ }
441
+ function initializerOf(reader, name) {
442
+ const { ts } = reader;
443
+ const declaration = resolvedDeclaration(reader, name);
444
+ if (!declaration || !ts.isVariableDeclaration(declaration) || !declaration.initializer) throw new WalkFailed();
445
+ return withoutAssertions(ts, declaration.initializer);
446
+ }
447
+ function literalValue(ts, node) {
448
+ if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
449
+ if (ts.isNumericLiteral(node)) return Number(node.text);
450
+ if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.MinusToken && ts.isNumericLiteral(node.operand)) return -Number(node.operand.text);
451
+ return node.kind === ts.SyntaxKind.NullKeyword ? null : void 0;
452
+ }
453
+ function walkArrayElements(reader, array, walking) {
454
+ const { ts } = reader;
455
+ if (!ts.isArrayLiteralExpression(array) || walking.has(array)) throw new WalkFailed();
456
+ walking.add(array);
457
+ const values = array.elements.flatMap((element) => {
458
+ if (ts.isSpreadElement(element)) return walkArrayElements(reader, initializerOf(reader, element.expression), walking);
459
+ const value = literalValue(ts, element);
460
+ if (value === void 0 || value === null) throw new WalkFailed();
461
+ return [value];
462
+ });
463
+ walking.delete(array);
464
+ return values;
465
+ }
466
+ function walkDeclaredType(reader, name, walking) {
467
+ const { ts, tc } = reader;
468
+ const declaration = resolvedDeclaration(reader, name);
469
+ if (declaration && ts.isTypeAliasDeclaration(declaration)) {
470
+ if (walking.has(declaration)) throw new WalkFailed();
471
+ walking.add(declaration);
472
+ const values = walkTypeNode(reader, declaration.type, walking);
473
+ walking.delete(declaration);
474
+ return values;
475
+ }
476
+ if (declaration && ts.isEnumDeclaration(declaration)) return declaration.members.map((member) => {
477
+ const value = tc.getConstantValue(member);
478
+ if (value === void 0) throw new WalkFailed();
479
+ return value;
480
+ });
481
+ throw new WalkFailed();
482
+ }
483
+ function walkPropertyAnnotation(reader, object, key, walking) {
484
+ const { ts, tc } = reader;
485
+ const annotated = tc.getPropertyOfType(tc.getTypeFromTypeNode(object), key)?.declarations?.find((declaration) => (ts.isPropertySignature(declaration) || ts.isPropertyDeclaration(declaration)) && declaration.type !== void 0);
486
+ if (!annotated?.type || walking.has(annotated)) throw new WalkFailed();
487
+ walking.add(annotated);
488
+ const values = walkTypeNode(reader, annotated.type, walking);
489
+ walking.delete(annotated);
490
+ return values;
491
+ }
492
+ function walkTypeNode(reader, node, walking) {
493
+ const { ts } = reader;
494
+ if (ts.isParenthesizedTypeNode(node)) return walkTypeNode(reader, node.type, walking);
495
+ if (ts.isUnionTypeNode(node)) return node.types.flatMap((member) => walkTypeNode(reader, member, walking));
496
+ if (node.kind === ts.SyntaxKind.UndefinedKeyword || node.kind === ts.SyntaxKind.NullKeyword || node.kind === ts.SyntaxKind.NeverKeyword) return [];
497
+ if (ts.isLiteralTypeNode(node)) {
498
+ const value = literalValue(ts, node.literal);
499
+ if (value === void 0) throw new WalkFailed();
500
+ return value === null ? [] : [value];
501
+ }
502
+ if (ts.isTypeReferenceNode(node)) return walkDeclaredType(reader, node.typeName, walking);
503
+ if (ts.isImportTypeNode(node)) {
504
+ if (!node.qualifier || node.isTypeOf) throw new WalkFailed();
505
+ return walkDeclaredType(reader, node.qualifier, walking);
506
+ }
507
+ if (ts.isTypeOperatorNode(node) && node.operator === ts.SyntaxKind.KeyOfKeyword && ts.isTypeQueryNode(node.type)) {
508
+ const object = initializerOf(reader, node.type.exprName);
509
+ if (!ts.isObjectLiteralExpression(object)) throw new WalkFailed();
510
+ return object.properties.map((property) => {
511
+ const key = property.name;
512
+ if (key && (ts.isIdentifier(key) || ts.isStringLiteral(key))) return key.text;
513
+ if (key && ts.isNumericLiteral(key)) return Number(key.text);
514
+ throw new WalkFailed();
515
+ });
516
+ }
517
+ if (ts.isIndexedAccessTypeNode(node)) {
518
+ const object = ts.isParenthesizedTypeNode(node.objectType) ? node.objectType.type : node.objectType;
519
+ if (ts.isTypeQueryNode(object) && node.indexType.kind === ts.SyntaxKind.NumberKeyword) return walkArrayElements(reader, initializerOf(reader, object.exprName), walking);
520
+ if (ts.isLiteralTypeNode(node.indexType) && ts.isStringLiteral(node.indexType.literal)) return walkPropertyAnnotation(reader, object, node.indexType.literal.text, walking);
521
+ }
522
+ throw new WalkFailed();
523
+ }
524
+ function inCodePointOrder(values) {
525
+ return [...values].sort((a, b) => compareCodePoints(String(a), String(b)) || Number(typeof a === "number") - Number(typeof b === "number"));
526
+ }
527
+ function orderedValues(reader, values, declarations) {
528
+ const { ts } = reader;
529
+ const annotations = declarations.flatMap((declaration) => (ts.isPropertySignature(declaration) || ts.isPropertyDeclaration(declaration)) && declaration.type ? [declaration.type] : []);
530
+ if (annotations.length === 0) return inCodePointOrder(values);
531
+ const walked = /* @__PURE__ */ new Map();
532
+ try {
533
+ for (const annotation of annotations) for (const value of walkTypeNode(reader, annotation, /* @__PURE__ */ new Set())) if (!walked.has(valueKey(value))) walked.set(valueKey(value), value);
534
+ } catch (error) {
535
+ if (error instanceof WalkFailed) return inCodePointOrder(values);
536
+ throw error;
537
+ }
538
+ return walked.size === values.length && values.every((value) => walked.has(valueKey(value))) ? [...walked.values()] : inCodePointOrder(values);
539
+ }
540
+ function annotationText({ ts }, declaration) {
541
+ if (ts.isMethodSignature(declaration)) {
542
+ if (!declaration.type) return void 0;
543
+ return declaration.getSourceFile().text.slice(declaration.parameters.pos - 1, declaration.type.end);
544
+ }
545
+ if (!("type" in declaration)) return void 0;
546
+ const annotation = declaration.type;
547
+ return annotation && ts.isTypeNode(annotation) ? annotation.getText() : void 0;
548
+ }
549
+ function printedType({ ts, tc }, types) {
550
+ const flags = ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.UseAliasDefinedOutsideCurrentScope;
551
+ const print = (type) => tc.typeToString(type, void 0, flags);
552
+ const printed = new Set(types.map(print));
553
+ if (printed.size === 1) return [...printed].join("");
554
+ const parts = [...new Set(types.map((type) => print(tc.getNonNullableType(type))))].map((text) => text.includes("=>") ? `(${text})` : text);
555
+ if (types.some((type) => (type.isUnion() ? type.types : [type]).some((part) => part.flags & ts.TypeFlags.Undefined))) parts.push("undefined");
556
+ return parts.join(" | ");
557
+ }
558
+ function propType(reader, declarations, types) {
559
+ const annotations = declarations.map((declaration) => annotationText(reader, declaration));
560
+ if (annotations.some((annotation) => annotation === void 0)) return [printedType(reader, types)];
561
+ const entries = annotations.map((annotation) => (annotation ?? "").replace(/\s+/g, " ").trim().replace(/^\| /, ""));
562
+ return [...new Set(entries)].filter((entry) => entry !== "never");
563
+ }
564
+ function declarationInBases(tc, type, name, seen = /* @__PURE__ */ new Set()) {
565
+ if (seen.has(type)) return void 0;
566
+ seen.add(type);
567
+ if (type.isUnionOrIntersection()) {
568
+ for (const part of type.types) {
569
+ const found = declarationInBases(tc, part, name, seen);
570
+ if (found) return found;
571
+ }
572
+ return;
573
+ }
574
+ const own = tc.getPropertyOfType(type, name)?.declarations?.find((declaration) => !inNodeModules(declaration));
575
+ if (own) return own;
576
+ if (!type.isClassOrInterface()) return void 0;
577
+ for (const base of tc.getBaseTypes(type)) {
578
+ const found = declarationInBases(tc, base, name, seen);
579
+ if (found) return found;
580
+ }
581
+ }
582
+ function packageOf(file) {
583
+ const segments = file.slice(file.lastIndexOf("/node_modules/") + 14).split("/");
584
+ return (segments[0] ?? "").startsWith("@") ? segments.slice(0, 2).join("/") : segments[0] ?? "";
585
+ }
586
+ function enclosingTypeName({ ts }, declaration) {
587
+ let node = declaration.parent;
588
+ while (node) {
589
+ if (ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node)) return node.name.text;
590
+ node = node.parent;
591
+ }
592
+ return "(anonymous)";
593
+ }
594
+ function readOwnProp(reader, name, symbols, recorded, optional, fallback) {
595
+ const { ts, tc, project } = reader;
596
+ const listed = symbols.flatMap((symbol) => symbol.declarations ?? []);
597
+ const declarations = [.../* @__PURE__ */ new Set([...listed.filter((declaration) => !inNodeModules(declaration)), recorded])].sort((a, b) => compareCodePoints(a.getSourceFile().fileName, b.getSourceFile().fileName) || a.pos - b.pos);
598
+ const types = symbols.map((symbol) => tc.getTypeOfSymbol(symbol));
599
+ const nameNode = ts.getNameOfDeclaration(recorded) ?? recorded;
600
+ const sourceFile = recorded.getSourceFile();
601
+ const file = relativeFile(project.root, sourceFile.fileName);
602
+ const position = positionOf(reader, sourceFile, nameNode.getStart());
603
+ if (!position) throw new Error(`no source position for prop ${name} in ${file}`);
604
+ const prop = {
605
+ name,
606
+ type: propType(reader, declarations, types),
607
+ optional,
608
+ file,
609
+ line: position.line,
610
+ column: position.column
611
+ };
612
+ if (fallback !== void 0) prop.default = fallback;
613
+ const values = literalValuesOfTypes(reader, types);
614
+ if (values) prop.values = orderedValues(reader, values, declarations);
615
+ const documented = symbols.find((symbol) => symbol.declarations?.includes(recorded)) ?? tc.getSymbolAtLocation(nameNode);
616
+ const doc = documented ? ts.displayPartsToString(documented.getDocumentationComment(tc)) : "";
617
+ if (doc !== "") prop.doc = doc;
618
+ return prop;
619
+ }
620
+ function readProps(reader, parameterType, sourceFile, defaults) {
621
+ const { ts, tc } = reader;
622
+ const branches = parameterType.isUnion() ? parameterType.types : [parameterType];
623
+ const grouped = /* @__PURE__ */ new Map();
624
+ for (const branch of branches) for (const symbol of tc.getPropertiesOfType(branch)) grouped.set(symbol.name, [...grouped.get(symbol.name) ?? [], symbol]);
625
+ const props = [];
626
+ const inherited = /* @__PURE__ */ new Map();
627
+ const inheritedDefaults = [];
628
+ const anyNames = [];
629
+ for (const [name, symbols] of grouped) {
630
+ const listed = symbols.flatMap((symbol) => symbol.declarations ?? []);
631
+ const recorded = listed.find((declaration) => declaration.getSourceFile() === sourceFile) ?? listed.find((declaration) => !inNodeModules(declaration)) ?? declarationInBases(tc, parameterType, name) ?? listed[0];
632
+ const fallback = defaults.get(name);
633
+ if (recorded && !inNodeModules(recorded)) {
634
+ const optional = symbols.length < branches.length || symbols.some((symbol) => (symbol.flags & ts.SymbolFlags.Optional) !== 0);
635
+ props.push(readOwnProp(reader, name, symbols, recorded, optional, fallback));
636
+ if (symbols.some((symbol) => tc.getTypeOfSymbol(symbol).flags & ts.TypeFlags.Any)) anyNames.push(name);
637
+ continue;
638
+ }
639
+ const pkg = recorded ? packageOf(recorded.getSourceFile().fileName) : "(synthetic)";
640
+ const type = recorded ? enclosingTypeName(reader, recorded) : "(synthetic)";
641
+ const key = `${pkg}\0${type}`;
642
+ const group = inherited.get(key) ?? {
643
+ package: pkg,
644
+ type,
645
+ count: 0
646
+ };
647
+ group.count += 1;
648
+ inherited.set(key, group);
649
+ if (fallback !== void 0) inheritedDefaults.push([name, fallback]);
650
+ }
651
+ return {
652
+ props: props.sort((a, b) => compareCodePoints(a.file, b.file) || a.line - b.line || a.column - b.column),
653
+ inherited: [...inherited.values()].sort((a, b) => compareCodePoints(a.package, b.package) || compareCodePoints(a.type, b.type)),
654
+ inheritedDefaults: Object.fromEntries(inheritedDefaults.sort(([a], [b]) => compareCodePoints(a, b))),
655
+ anyNames
656
+ };
657
+ }
658
+ function propsOfSignature(reader, signature, sourceFile, defaults) {
659
+ const parameter = signature.parameters[0];
660
+ return parameter ? readProps(reader, reader.tc.getTypeOfSymbol(parameter), sourceFile, defaults) : {
661
+ props: [],
662
+ inherited: [],
663
+ inheritedDefaults: {},
664
+ anyNames: []
665
+ };
666
+ }
667
+ function ownPropNames(reader, component, sourceFile) {
668
+ const signature = reader.tc.getTypeOfSymbol(component).getCallSignatures()[0];
669
+ if (!signature) return [];
670
+ return propsOfSignature(reader, signature, sourceFile, /* @__PURE__ */ new Map()).props.map(({ name }) => name);
671
+ }
672
+ function intelligenceBlock(reader, sourceFile) {
673
+ const { ts } = reader;
674
+ const blocks = [];
675
+ const visit = (node) => {
676
+ blocks.push(...node.jsDoc ?? []);
677
+ ts.forEachChild(node, visit);
678
+ };
679
+ visit(sourceFile);
680
+ return blocks.flatMap((block) => {
681
+ const start = block.getStart();
682
+ const at = sourceFile.fileName.endsWith(".astro") ? sourceOffset(reader, sourceFile.fileName, start) : start;
683
+ return at === void 0 ? [] : [{
684
+ block,
685
+ at
686
+ }];
687
+ }).sort((a, b) => a.at - b.at)[0]?.block;
688
+ }
689
+ function intelligence(reader, sourceFile) {
690
+ const { ts } = reader;
691
+ const block = intelligenceBlock(reader, sourceFile);
692
+ if (!block) return { tags: [] };
693
+ const tags = (block.tags ?? []).map((tag) => ({
694
+ name: tag.tagName.text,
695
+ text: ts.getTextOfJSDocComment(tag.comment) ?? ""
696
+ }));
697
+ const description = ts.getTextOfJSDocComment(block.comment);
698
+ return description ? {
699
+ description,
700
+ tags
701
+ } : { tags };
702
+ }
703
+ async function parseErrorReason(reader, sourceFile) {
704
+ const { ts, project } = reader;
705
+ const file = sourceFile.fileName;
706
+ if (!file.endsWith(".astro")) return void 0;
707
+ const root = scriptOf(reader, file)?.generated?.root;
708
+ const compiler = root && "compilerDiagnostics" in root ? root.compilerDiagnostics : void 0;
709
+ if (!(Array.isArray(compiler) && compiler.some((diagnostic) => diagnostic.severity === 1))) return void 0;
710
+ const syntactic = new Set(project.program().getSyntacticDiagnostics(sourceFile).map((diagnostic) => ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")));
711
+ return (await project.checker.check(file)).filter(({ severity, source, message }) => (severity === void 0 || severity === 1) && (source === "astro" || source === "ts" && typeof message === "string" && syntactic.has(message))).sort((a, b) => a.range.start.line - b.range.start.line || a.range.start.character - b.range.start.character).map(({ message }) => message).join("; ");
712
+ }
713
+ async function componentsOfFile(reader, file) {
714
+ const { ts, tc, project } = reader;
715
+ const sourceFile = project.program().getSourceFile(file);
716
+ const moduleSymbol = sourceFile && tc.getSymbolAtLocation(sourceFile);
717
+ if (!sourceFile || !moduleSymbol) return [];
718
+ const exportNames = /* @__PURE__ */ new Map();
719
+ for (const exported of tc.getExportsOfModule(moduleSymbol)) {
720
+ const symbol = exported.flags & ts.SymbolFlags.Alias ? tc.getAliasedSymbol(exported) : exported;
721
+ if (symbol.flags & ts.SymbolFlags.Value) exportNames.set(symbol, [...exportNames.get(symbol) ?? [], exported.name]);
722
+ }
723
+ const isAstro = file.endsWith(".astro");
724
+ const relative = relativeFile(project.root, file);
725
+ const { description, tags } = intelligence(reader, sourceFile);
726
+ const parseReason = await parseErrorReason(reader, sourceFile);
727
+ const components = [];
728
+ for (const [symbol, names] of exportNames) {
729
+ const name = names.filter((n) => /^[A-Z]/.test(n)).sort(compareCodePoints)[0];
730
+ const signature = tc.getTypeOfSymbol(symbol).getCallSignatures()[0];
731
+ if (name === void 0 || !signature) continue;
732
+ let defaults = /* @__PURE__ */ new Map();
733
+ if (!isAstro) defaults = tsxDefaults(reader, symbol.valueDeclaration);
734
+ else if (names.includes("default")) defaults = astroDefaults(ts, sourceFile);
735
+ const read = propsOfSignature(reader, signature, sourceFile, defaults);
736
+ const component = {
737
+ name,
738
+ file: relative,
739
+ resolved: true,
740
+ tags,
741
+ props: read.props,
742
+ inherited: read.inherited,
743
+ inheritedDefaults: read.inheritedDefaults
744
+ };
745
+ if (description !== void 0) component.description = description;
746
+ if (parseReason !== void 0) {
747
+ component.resolved = false;
748
+ component.reason = parseReason;
749
+ } else if (read.anyNames.length > 0) {
750
+ component.resolved = false;
751
+ component.reason = `props typed any: ${read.anyNames.join(", ")}`;
752
+ }
753
+ components.push(component);
754
+ }
755
+ return components;
756
+ }
757
+ async function resolveComponents(project, componentFolders) {
758
+ const reader = {
759
+ project,
760
+ ts: project.ts,
761
+ tc: project.program().getTypeChecker()
762
+ };
763
+ const files = /* @__PURE__ */ new Set();
764
+ for (const folder of componentFolders) await walkFolder(path.resolve(project.root, folder), files);
765
+ const rootFiles = new Set(project.checker.getRootFileNames().map(posix));
766
+ const components = [];
767
+ const notices = [];
768
+ for (const file of files) if (rootFiles.has(file)) components.push(...await componentsOfFile(reader, file));
769
+ else notices.push({
770
+ code: "outside-program",
771
+ message: `${relativeFile(project.root, file)} is under componentsPath but not in the tsconfig's files`
772
+ });
773
+ components.sort((a, b) => compareCodePoints(a.file, b.file) || compareCodePoints(a.name, b.name));
774
+ return {
775
+ components,
776
+ notices
777
+ };
778
+ }
779
+ //#endregion
780
+ //#region src/lint.ts
781
+ const CLASS_ATTRIBUTES = /* @__PURE__ */ new Set([
782
+ "class",
783
+ "className",
784
+ "class:list"
785
+ ]);
786
+ const MAX_RESOLVE_STEPS = 8;
787
+ const realPath = (file) => existsSync(file) ? realpathSync(file) : file;
788
+ function offsetAt(text, line, column) {
789
+ const breaks = /\r\n|\r|\n/g;
790
+ let start = 0;
791
+ for (let at = 1; at < line && breaks.exec(text); at += 1) start = breaks.lastIndex;
792
+ return start + column - 1;
793
+ }
794
+ function programOffset(reader, sourceFile, diagnostic) {
795
+ const file = sourceFile.fileName;
796
+ if (!file.endsWith(".astro")) return offsetAt(sourceFile.text, diagnostic.line, diagnostic.column);
797
+ const snapshot = scriptOf(reader, file)?.snapshot;
798
+ if (!snapshot) return void 0;
799
+ return generatedOffset(reader, file, offsetAt(snapshot.getText(0, snapshot.getLength()), diagnostic.line, diagnostic.column));
800
+ }
801
+ function innermostNode(ts, sourceFile, offset) {
802
+ let node = sourceFile;
803
+ for (;;) {
804
+ let inner;
805
+ ts.forEachChild(node, (child) => {
806
+ if (child.getStart(sourceFile) <= offset && offset < child.end) inner = child;
807
+ });
808
+ if (!inner) return node;
809
+ node = inner;
810
+ }
811
+ }
812
+ function elementUsing(ts, node) {
813
+ if (ts.isSourceFile(node)) return void 0;
814
+ const { parent } = node;
815
+ if (ts.isJsxAttribute(parent) && parent.name === node) return parent.parent.parent;
816
+ const tag = ts.isPropertyAccessExpression(parent) && parent.name === node ? parent : node;
817
+ const element = tag.parent;
818
+ return ts.isJsxOpeningLikeElement(element) && element.tagName === tag ? element : void 0;
819
+ }
820
+ function resolveTag({ ts, tc }, { tagName }) {
821
+ let symbol = tc.getSymbolAtLocation(ts.isPropertyAccessExpression(tagName) ? tagName.name : tagName);
822
+ for (let step = 0; symbol && step < MAX_RESOLVE_STEPS; step += 1) {
823
+ const declaration = symbol.valueDeclaration;
824
+ if (symbol.flags & ts.SymbolFlags.Alias) symbol = tc.getAliasedSymbol(symbol);
825
+ else if (declaration && ts.isVariableDeclaration(declaration) && declaration.initializer && ts.isIdentifier(declaration.initializer)) symbol = tc.getSymbolAtLocation(declaration.initializer);
826
+ else return symbol;
827
+ }
828
+ }
829
+ function deprecatedText({ ts, tc }, element, name) {
830
+ const parameter = tc.getResolvedSignature(element)?.parameters[0];
831
+ const tag = (parameter && tc.getTypeOfSymbol(parameter).getProperty(name))?.getJsDocTags(tc).find((found) => found.name === "deprecated");
832
+ return tag ? ts.displayPartsToString(tag.text) || void 0 : void 0;
833
+ }
834
+ function utilityOf(className) {
835
+ let depth = 0;
836
+ let start = 0;
837
+ for (let at = 0; at < className.length; at += 1) {
838
+ const character = className[at];
839
+ if (character === "[" || character === "(") depth += 1;
840
+ else if (character === "]" || character === ")") depth -= 1;
841
+ else if (character === ":" && depth === 0) start = at + 1;
842
+ }
843
+ return className.slice(start);
844
+ }
845
+ function classLiterals(ts, node) {
846
+ if (ts.isStringLiteralLike(node)) return [node];
847
+ if (ts.isJsxExpression(node) || ts.isParenthesizedExpression(node)) return node.expression ? classLiterals(ts, node.expression) : [];
848
+ if (ts.isArrayLiteralExpression(node)) return node.elements.flatMap((element) => classLiterals(ts, element));
849
+ if (ts.isObjectLiteralExpression(node)) return node.properties.flatMap((property) => ts.isPropertyAssignment(property) && ts.isStringLiteral(property.name) ? [property.name] : []);
850
+ return [];
851
+ }
852
+ function bracketsInLiteral(reader, file, sourceFile, literal) {
853
+ return [...literal.getText(sourceFile).slice(1, -1).matchAll(/\S+/g)].flatMap((match) => {
854
+ const [className] = match;
855
+ if (!utilityOf(className).includes("[")) return [];
856
+ const position = positionOf(reader, sourceFile, literal.getStart(sourceFile) + 1 + match.index);
857
+ if (!position) return [];
858
+ return [{
859
+ file,
860
+ line: position.line,
861
+ column: position.column,
862
+ endLine: position.line,
863
+ endColumn: position.column + className.length,
864
+ severity: "error",
865
+ code: "rafters(arbitrary-value)",
866
+ message: `${className} is an arbitrary value`
867
+ }];
868
+ });
869
+ }
870
+ function bracketValues(reader, file, sourceFile) {
871
+ const { ts } = reader;
872
+ const found = [];
873
+ const visit = (node) => {
874
+ if (ts.isJsxAttribute(node) && node.initializer) {
875
+ const { name } = node;
876
+ const attribute = ts.isJsxNamespacedName(name) ? `${name.namespace.text}:${name.name.text}` : name.text;
877
+ if (CLASS_ATTRIBUTES.has(attribute)) for (const literal of classLiterals(ts, node.initializer)) found.push(...bracketsInLiteral(reader, file, sourceFile, literal));
878
+ }
879
+ ts.forEachChild(node, visit);
880
+ };
881
+ visit(sourceFile);
882
+ return found;
883
+ }
884
+ const FILL_WORD = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
885
+ const FILL_ALPHA = /^(100|[1-9]?[0-9])$/;
886
+ const AUTHORED_FILL = "a fill the designer authors, fill=\"bg-fill-<name>\"";
887
+ const isFillStop = (stop) => {
888
+ const [word = "", alpha, ...rest] = stop.split("/");
889
+ return FILL_WORD.test(word) && (alpha === void 0 || FILL_ALPHA.test(alpha)) && rest.length === 0;
890
+ };
891
+ function retiredFillForm(value) {
892
+ if (value.startsWith("bg-fill-")) return void 0;
893
+ if (FILL_WORD.test(value) && !value.includes("-to-")) return "bare";
894
+ return value.split("-to-").length <= 2 && value.split("-to-").every(isFillStop) ? "composed" : void 0;
895
+ }
896
+ async function loadSurfaces(root) {
897
+ try {
898
+ const { surfaceWords } = await import("./tokens-CYaadJgI.mjs");
899
+ return { words: surfaceWords(root) };
900
+ } catch (error) {
901
+ return { failure: error instanceof Error ? error.message : String(error) };
902
+ }
903
+ }
904
+ function fillLiteral(ts, node) {
905
+ const { initializer } = node;
906
+ if (!initializer) return void 0;
907
+ if (ts.isStringLiteral(initializer)) return initializer;
908
+ const inner = ts.isJsxExpression(initializer) ? initializer.expression : void 0;
909
+ return inner && ts.isStringLiteralLike(inner) ? inner : void 0;
910
+ }
911
+ function fillAttributes({ ts }, sourceFile) {
912
+ const found = [];
913
+ const visit = (node) => {
914
+ if (ts.isJsxAttribute(node) && ts.isIdentifier(node.name) && node.name.text === "fill") found.push(node);
915
+ ts.forEachChild(node, visit);
916
+ };
917
+ visit(sourceFile);
918
+ return found;
919
+ }
920
+ async function lint(project, options) {
921
+ const files = options.files ?? project.checker.getRootFileNames().filter((file) => file.endsWith(".tsx") || file.endsWith(".astro")).map((file) => relativeFile(project.root, file));
922
+ const perFile = [];
923
+ for (const file of files) perFile.push([file, await project.diagnostics(file)]);
924
+ const program = project.program();
925
+ const reader = {
926
+ project,
927
+ ts: project.ts,
928
+ tc: program.getTypeChecker()
929
+ };
930
+ const { ts } = reader;
931
+ const folders = options.componentFolders.map((folder) => realPath(path.resolve(project.root, folder)) + path.sep);
932
+ const isUnderFolder = (file) => {
933
+ const real = realPath(file);
934
+ return folders.some((folder) => real.startsWith(folder));
935
+ };
936
+ const propsHelp = /* @__PURE__ */ new Map();
937
+ const reportedUse = (sourceFile, diagnostic) => {
938
+ const offset = programOffset(reader, sourceFile, diagnostic);
939
+ if (offset === void 0) return void 0;
940
+ const node = innermostNode(ts, sourceFile, offset);
941
+ const element = elementUsing(ts, node);
942
+ const component = element && resolveTag(reader, element);
943
+ const declaration = component?.valueDeclaration ?? component?.declarations?.[0];
944
+ if (!element || !component || !declaration) return void 0;
945
+ const declaredIn = declaration.getSourceFile();
946
+ if (!isUnderFolder(declaredIn.fileName)) return void 0;
947
+ let help;
948
+ if (diagnostic.code === "ts(6385)") help = deprecatedText(reader, element, node.getText(sourceFile));
949
+ else {
950
+ help = propsHelp.get(component);
951
+ if (help === void 0) {
952
+ help = ownPropNames(reader, component, declaredIn).join(", ");
953
+ propsHelp.set(component, help);
954
+ }
955
+ }
956
+ return help ? {
957
+ ...diagnostic,
958
+ help
959
+ } : diagnostic;
960
+ };
961
+ let surfaces;
962
+ const replacement = async (value, form) => {
963
+ if (form === "composed") return AUTHORED_FILL;
964
+ surfaces ??= loadSurfaces(project.root);
965
+ const loaded = await surfaces;
966
+ if ("failure" in loaded) return `the project's tokens could not be loaded, so no replacement is named: ${loaded.failure}`;
967
+ return loaded.words.has(value) ? `surface="${value}"` : AUTHORED_FILL;
968
+ };
969
+ const retiredFills = async (file, sourceFile) => {
970
+ const flagged = [];
971
+ for (const attribute of fillAttributes(reader, sourceFile)) {
972
+ const literal = fillLiteral(ts, attribute);
973
+ const form = literal && retiredFillForm(literal.text);
974
+ if (!literal || !form) continue;
975
+ const component = resolveTag(reader, attribute.parent.parent);
976
+ const declaration = component?.valueDeclaration ?? component?.declarations?.[0];
977
+ if (!declaration || !isUnderFolder(declaration.getSourceFile().fileName)) continue;
978
+ const start = positionOf(reader, sourceFile, attribute.getStart(sourceFile));
979
+ const end = positionOf(reader, sourceFile, attribute.end);
980
+ if (!start || !end) continue;
981
+ flagged.push({
982
+ file,
983
+ line: start.line,
984
+ column: start.column,
985
+ endLine: end.line,
986
+ endColumn: end.column,
987
+ severity: "error",
988
+ code: "rafters(retired-fill)",
989
+ message: `fill="${literal.text}" is a retired fill value`,
990
+ help: await replacement(literal.text, form)
991
+ });
992
+ }
993
+ return flagged;
994
+ };
995
+ const found = [];
996
+ for (const [file, diagnostics] of perFile) {
997
+ const absolute = path.join(project.root, file);
998
+ const sourceFile = program.getSourceFile(absolute);
999
+ if (!sourceFile) continue;
1000
+ for (const diagnostic of diagnostics) {
1001
+ const reported = reportedUse(sourceFile, diagnostic);
1002
+ if (reported) found.push(reported);
1003
+ }
1004
+ if (!isUnderFolder(absolute)) {
1005
+ found.push(...bracketValues(reader, file, sourceFile));
1006
+ found.push(...await retiredFills(file, sourceFile));
1007
+ }
1008
+ }
1009
+ return found.sort((a, b) => compareCodePoints(a.file, b.file) || a.line - b.line || a.column - b.column);
1010
+ }
1011
+ function firstLine(message) {
1012
+ return (typeof message === "string" ? message : message.value).split(/\r\n|\r|\n/, 1)[0] ?? "";
1013
+ }
1014
+ function report(diagnostics) {
1015
+ const lines = diagnostics.flatMap(({ file, line, column, severity, code, message, help }) => {
1016
+ const entry = `${file}:${line}:${column} ${severity} ${code} ${firstLine(message)}`;
1017
+ return help === void 0 ? [entry] : [entry, ` help: ${help}`];
1018
+ });
1019
+ const count = diagnostics.length;
1020
+ lines.push(count === 1 ? "1 problem" : `${count} problems`);
1021
+ return lines.map((line) => `${line}\n`).join("");
1022
+ }
1023
+ //#endregion
1024
+ export { ProjectError as a, resolveComponents as i, report as n, openProject as o, compareCodePoints as r, readConfig as s, lint as t };