@valbuild/language-server 0.115.0 → 0.117.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.
- package/CHANGELOG.md +61 -0
- package/dist/declarations/src/diagnostics.d.ts +11 -1
- package/dist/declarations/src/mediaMetadataChecks.d.ts +105 -0
- package/dist/valbuild-language-server.cjs.dev.js +364 -1
- package/dist/valbuild-language-server.cjs.prod.js +364 -1
- package/dist/valbuild-language-server.esm.js +365 -2
- package/package.json +5 -4
|
@@ -2,7 +2,7 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import ts from 'typescript';
|
|
4
4
|
import { Internal, DEFAULT_VAL_REMOTE_HOST, DEFAULT_CONTENT_HOST } from '@valbuild/core';
|
|
5
|
-
import { fixHandlers, createService, analyzeValModule, parsePersonalAccessTokenFile, getPersonalAccessTokenPath, startValLogin, awaitValLoginConfirmation, persistPersonalAccessToken, ValLoginError, findAndEvalValConfigFile,
|
|
5
|
+
import { fixHandlers, createService, analyzeValModule, createFixPatch, parsePersonalAccessTokenFile, getPersonalAccessTokenPath, startValLogin, awaitValLoginConfirmation, persistPersonalAccessToken, ValLoginError, findAndEvalValConfigFile, patchSourceFile, getSettings, uploadRemoteFile, findJsonEntryFilePath, rebaseContentOp, classifyJsonValuesOp, extractImageMetadata, extractFileMetadata } from '@valbuild/server';
|
|
6
6
|
import { DiagnosticSeverity, ShowDocumentRequest, ApplyWorkspaceEditRequest, CodeActionKind, CodeAction, MarkupContent, CompletionItemKind, DidChangeWatchedFilesNotification } from 'vscode-languageserver';
|
|
7
7
|
import { TextDocuments, TextDocumentSyncKind, createConnection, ProposedFeatures } from 'vscode-languageserver/node';
|
|
8
8
|
import { TextDocument } from 'vscode-languageserver-textdocument';
|
|
@@ -846,6 +846,314 @@ function traverseObjectLiteral(node, sourceFile) {
|
|
|
846
846
|
return map;
|
|
847
847
|
}
|
|
848
848
|
|
|
849
|
+
/**
|
|
850
|
+
* Adjudicating the media metadata placeholders core emits unconditionally.
|
|
851
|
+
*
|
|
852
|
+
* `ImageSchema.validate` cannot read bytes, so it never answers "does the
|
|
853
|
+
* stored width/height/mimeType match the file". It defers instead: any
|
|
854
|
+
* `s.image()` carrying metadata gets an `image:check-metadata` error whether
|
|
855
|
+
* or not anything is wrong (`packages/core/src/schema/image.ts`), and
|
|
856
|
+
* `s.file()` does the same with `file:check-metadata`.
|
|
857
|
+
*
|
|
858
|
+
* `val validate` resolves those by running the fix handler and then
|
|
859
|
+
* `createFixPatch` in report mode, which compares each field against the file
|
|
860
|
+
* and returns one error per field that disagrees. The Studio cannot do that at
|
|
861
|
+
* all -- a browser has no filesystem -- so it drops them wholesale
|
|
862
|
+
* (`partitionValidationErrors` in `@valbuild/shared`).
|
|
863
|
+
*
|
|
864
|
+
* An editor is in the CLI's position, not the browser's, and publishing the
|
|
865
|
+
* placeholders raw put a permanent warning on every image in the project. So
|
|
866
|
+
* they are adjudicated here, by the same comparison `val validate` makes, and
|
|
867
|
+
* only a real disagreement is shown.
|
|
868
|
+
*/
|
|
869
|
+
/**
|
|
870
|
+
* The fixes that carry an unconditional metadata placeholder.
|
|
871
|
+
*
|
|
872
|
+
* `*:add-metadata` is deliberately absent: it is emitted only when every
|
|
873
|
+
* metadata field is missing, which needs no adjudication -- there is nothing
|
|
874
|
+
* stored to compare, and the error stands on its own.
|
|
875
|
+
*/
|
|
876
|
+
const METADATA_CHECK_FIXES = ["image:check-metadata", "file:check-metadata"];
|
|
877
|
+
|
|
878
|
+
/** One field of a media value that disagrees with the file behind it. */
|
|
879
|
+
|
|
880
|
+
/**
|
|
881
|
+
* The verdict on one placeholder. Empty means the metadata agrees with the
|
|
882
|
+
* file and nothing should be published.
|
|
883
|
+
*/
|
|
884
|
+
|
|
885
|
+
/**
|
|
886
|
+
* Whether this error is the unconditional deferral rather than a real finding.
|
|
887
|
+
*
|
|
888
|
+
* This is the whole difficulty of the change. `image:check-metadata` is
|
|
889
|
+
* attached to FIVE different image errors, and only the last is a placeholder:
|
|
890
|
+
*
|
|
891
|
+
* 1. `Invalid mime type format` -- `accept` set, mimeType has no `/`
|
|
892
|
+
* 2. `Mime type mismatch` -- `accept` set and not satisfied
|
|
893
|
+
* 3. `Could not determine mime type from file extension`
|
|
894
|
+
* 4. `Mime type and file extension not matching`
|
|
895
|
+
* 5. the fall-through deferral
|
|
896
|
+
*
|
|
897
|
+
* The first four are real: they are about the mime type disagreeing with the
|
|
898
|
+
* schema or with the filename, neither of which reading the file can settle.
|
|
899
|
+
* Adjudicating one of them would find the stored metadata matches the bytes and
|
|
900
|
+
* drop a genuine error -- so they have to be told apart before any file is read.
|
|
901
|
+
*
|
|
902
|
+
* There is no flag on `ValidationError` saying which is which, so the four
|
|
903
|
+
* conditions are re-derived here from the same inputs core used. They are
|
|
904
|
+
* transcribed from `ImageSchema.executeValidate`, in its order, and
|
|
905
|
+
* `mediaMetadataChecks.test.ts` drives real core through all five cases to
|
|
906
|
+
* check that this agrees with it. If core grows a sixth condition, that test is
|
|
907
|
+
* what catches it.
|
|
908
|
+
*
|
|
909
|
+
* `FileSchema` needs none of this: its four equivalent errors carry no `fixes`
|
|
910
|
+
* at all, so `file:check-metadata` is unambiguous. The test pins that too.
|
|
911
|
+
*/
|
|
912
|
+
function isDeferredMediaMetadataCheck({
|
|
913
|
+
error,
|
|
914
|
+
schema
|
|
915
|
+
}) {
|
|
916
|
+
const fixes = error.fixes ?? [];
|
|
917
|
+
if (!fixes.some(fix => METADATA_CHECK_FIXES.includes(fix))) {
|
|
918
|
+
return false;
|
|
919
|
+
}
|
|
920
|
+
if (fixes.includes("file:check-metadata")) {
|
|
921
|
+
return true;
|
|
922
|
+
}
|
|
923
|
+
const value = mediaValueOf(error.value);
|
|
924
|
+
if (typeof value?.path !== "string") {
|
|
925
|
+
// Nothing to re-derive the conditions from. Keep the error: claiming an
|
|
926
|
+
// image is fine on no evidence is the worse failure.
|
|
927
|
+
return false;
|
|
928
|
+
}
|
|
929
|
+
const accept = acceptOf(schema);
|
|
930
|
+
// Core reads `src.mimeType ?? ""`, and every condition below is guarded on
|
|
931
|
+
// it being non-empty, so an absent mimeType passes all four.
|
|
932
|
+
const mimeType = typeof value.mimeType === "string" ? value.mimeType : "";
|
|
933
|
+
if (accept && mimeType && !mimeType.includes("/")) {
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
936
|
+
if (accept && mimeType && mimeType.includes("/") && !Internal.mimeTypeMatchesAccept(mimeType, accept)) {
|
|
937
|
+
return false;
|
|
938
|
+
}
|
|
939
|
+
const fileMimeType = Internal.filenameToMimeType(value.path);
|
|
940
|
+
if (!fileMimeType) {
|
|
941
|
+
return false;
|
|
942
|
+
}
|
|
943
|
+
if (mimeType && fileMimeType !== mimeType) {
|
|
944
|
+
return false;
|
|
945
|
+
}
|
|
946
|
+
return true;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
/**
|
|
950
|
+
* {@link isDeferredMediaMetadataCheck} for an error in a module, resolving the
|
|
951
|
+
* schema it needs.
|
|
952
|
+
*
|
|
953
|
+
* Both the adjudicator and `createValDiagnostics` have to make the same call,
|
|
954
|
+
* on the same inputs -- one to decide what to adjudicate, the other to decide
|
|
955
|
+
* what to publish -- so it lives here rather than being written out twice.
|
|
956
|
+
*/
|
|
957
|
+
function isDeferredMediaMetadataCheckAt({
|
|
958
|
+
sourcePath,
|
|
959
|
+
error,
|
|
960
|
+
content
|
|
961
|
+
}) {
|
|
962
|
+
return isDeferredMediaMetadataCheck({
|
|
963
|
+
error,
|
|
964
|
+
schema: resolveSchemaAt$1(sourcePath, content)
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
/**
|
|
969
|
+
* Adjudicate every deferred metadata placeholder in `validation`.
|
|
970
|
+
*
|
|
971
|
+
* Async, and therefore separate from `createValDiagnostics`, which stays
|
|
972
|
+
* synchronous so it can be tested without a project -- the same split
|
|
973
|
+
* `resolveGalleryChecks` uses. The caller runs this first and passes the
|
|
974
|
+
* result in.
|
|
975
|
+
*/
|
|
976
|
+
async function resolveMediaMetadataChecks({
|
|
977
|
+
validation,
|
|
978
|
+
content,
|
|
979
|
+
valRoot,
|
|
980
|
+
remoteHost = process.env.VAL_REMOTE_HOST || DEFAULT_VAL_REMOTE_HOST
|
|
981
|
+
}) {
|
|
982
|
+
const verdicts = new Map();
|
|
983
|
+
for (const [sourcePath, errors] of Object.entries(validation)) {
|
|
984
|
+
for (const error of errors) {
|
|
985
|
+
if (!isDeferredMediaMetadataCheckAt({
|
|
986
|
+
sourcePath,
|
|
987
|
+
error,
|
|
988
|
+
content
|
|
989
|
+
})) {
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
const key = mediaMetadataCheckKey(sourcePath, error);
|
|
993
|
+
try {
|
|
994
|
+
verdicts.set(key, await adjudicate({
|
|
995
|
+
sourcePath,
|
|
996
|
+
error,
|
|
997
|
+
content,
|
|
998
|
+
valRoot,
|
|
999
|
+
remoteHost
|
|
1000
|
+
}));
|
|
1001
|
+
} catch {
|
|
1002
|
+
// This runs inside `validate`, which publishes NOTHING if it throws --
|
|
1003
|
+
// one bad image would silently clear every Val diagnostic in the file.
|
|
1004
|
+
// Keep the placeholder rather than claiming the metadata is fine.
|
|
1005
|
+
verdicts.set(key, keep(error));
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
return verdicts;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* Key for one placeholder. A value can in principle carry more than one, so
|
|
1014
|
+
* the fix names are part of the key -- as they are for the gallery checks.
|
|
1015
|
+
*/
|
|
1016
|
+
function mediaMetadataCheckKey(sourcePath, error) {
|
|
1017
|
+
return `${sourcePath}|${(error.fixes ?? []).join(",")}`;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
/** Keeping the placeholder: what to publish when we learned nothing. */
|
|
1021
|
+
function keep(error) {
|
|
1022
|
+
return [{
|
|
1023
|
+
message: error.message,
|
|
1024
|
+
...(error.fixes ? {
|
|
1025
|
+
fixes: error.fixes
|
|
1026
|
+
} : {}),
|
|
1027
|
+
...(error.value !== undefined ? {
|
|
1028
|
+
value: error.value
|
|
1029
|
+
} : {})
|
|
1030
|
+
}];
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
/**
|
|
1034
|
+
* What `createFixPatch` says about one placeholder, in report mode.
|
|
1035
|
+
*
|
|
1036
|
+
* `val validate` runs the fix handler first and then `createFixPatch`, but for
|
|
1037
|
+
* these four fixes the handler is `handleFileMetadata`, whose whole job is the
|
|
1038
|
+
* precondition "the ref resolves and the file is on disk". That precondition is
|
|
1039
|
+
* checked directly here instead, for two reasons:
|
|
1040
|
+
*
|
|
1041
|
+
* - `createValDiagnostics` already reports a missing file as
|
|
1042
|
+
* `val/file-not-found`, which is a better diagnostic than a metadata
|
|
1043
|
+
* mismatch and is produced before this verdict is consulted.
|
|
1044
|
+
* - `handleFileMetadata` resolves the source path through the module, and that
|
|
1045
|
+
* throws outright for a `.jsonValues()` entry ("Cannot resolve path into a
|
|
1046
|
+
* jsonValues entry until its content is loaded") -- so routing through it
|
|
1047
|
+
* would leave every entry-backed image stuck on the placeholder.
|
|
1048
|
+
*
|
|
1049
|
+
* The comparison itself is still `createFixPatch`, unchanged, which is the
|
|
1050
|
+
* parity that matters: the editor's wording is the CLI's wording because it is
|
|
1051
|
+
* the CLI's code -- including for bytes it cannot measure, where it reports
|
|
1052
|
+
* what `val validate` reports rather than a second opinion of our own.
|
|
1053
|
+
*
|
|
1054
|
+
* `createFixPatch` reads and decodes the image itself, so this is one file read
|
|
1055
|
+
* per media field per validation pass, and nothing here should add another.
|
|
1056
|
+
*/
|
|
1057
|
+
async function adjudicate({
|
|
1058
|
+
sourcePath,
|
|
1059
|
+
error,
|
|
1060
|
+
content,
|
|
1061
|
+
valRoot,
|
|
1062
|
+
remoteHost
|
|
1063
|
+
}) {
|
|
1064
|
+
const ref = mediaValueOf(error.value)?.path;
|
|
1065
|
+
if (typeof ref !== "string") {
|
|
1066
|
+
return keep(error);
|
|
1067
|
+
}
|
|
1068
|
+
// A remote ref is a URL and is not expected on disk. Core does not emit these
|
|
1069
|
+
// fixes for one, but a stale ref should not be reported as a local mismatch.
|
|
1070
|
+
if (Internal.remote.splitRemoteRef(ref).status === "success") {
|
|
1071
|
+
return keep(error);
|
|
1072
|
+
}
|
|
1073
|
+
if (!fs.existsSync(path.join(valRoot, ref))) {
|
|
1074
|
+
// Reported as `val/file-not-found` instead; keeping the placeholder here
|
|
1075
|
+
// means this verdict never has the last word on a file that is not there.
|
|
1076
|
+
return keep(error);
|
|
1077
|
+
}
|
|
1078
|
+
let fixed;
|
|
1079
|
+
try {
|
|
1080
|
+
fixed = await createFixPatch({
|
|
1081
|
+
projectRoot: valRoot,
|
|
1082
|
+
remoteHost
|
|
1083
|
+
},
|
|
1084
|
+
// `false`: this is a question, not a fix. Asking for the patch would have
|
|
1085
|
+
// createFixPatch read and rewrite files behind the editor's back.
|
|
1086
|
+
false, sourcePath, error, {}, content.source, content.schema);
|
|
1087
|
+
} catch {
|
|
1088
|
+
return keep(error);
|
|
1089
|
+
}
|
|
1090
|
+
return (fixed?.remainingErrors ?? []).map(remaining => ({
|
|
1091
|
+
message: remaining.message,
|
|
1092
|
+
// `createFixPatch` clears `fixes` on the per-field errors it reports, but
|
|
1093
|
+
// the fix is still available and still the remedy -- it is what the
|
|
1094
|
+
// placeholder was asking for. Carrying the placeholder's own fixes is what
|
|
1095
|
+
// keeps the "update image metadata" quick fix offered, and the diagnostic
|
|
1096
|
+
// a Warning rather than an Error.
|
|
1097
|
+
...(error.fixes ? {
|
|
1098
|
+
fixes: error.fixes
|
|
1099
|
+
} : {}),
|
|
1100
|
+
...(error.value !== undefined ? {
|
|
1101
|
+
value: error.value
|
|
1102
|
+
} : {})
|
|
1103
|
+
}));
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
/**
|
|
1107
|
+
* The `accept` a media schema declares, if any.
|
|
1108
|
+
*
|
|
1109
|
+
* Read from the serialized schema (`SerializedImageSchema.options`) rather
|
|
1110
|
+
* than from a schema instance: this runs against what `Service.get` returns.
|
|
1111
|
+
*/
|
|
1112
|
+
function acceptOf(schema) {
|
|
1113
|
+
if (typeof schema !== "object" || schema === null || !("options" in schema)) {
|
|
1114
|
+
return undefined;
|
|
1115
|
+
}
|
|
1116
|
+
const {
|
|
1117
|
+
options
|
|
1118
|
+
} = schema;
|
|
1119
|
+
if (typeof options !== "object" || options === null || !("accept" in options)) {
|
|
1120
|
+
return undefined;
|
|
1121
|
+
}
|
|
1122
|
+
const {
|
|
1123
|
+
accept
|
|
1124
|
+
} = options;
|
|
1125
|
+
return typeof accept === "string" ? accept : undefined;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
/** A media value, read as a plain record. */
|
|
1129
|
+
function mediaValueOf(value) {
|
|
1130
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
1131
|
+
return undefined;
|
|
1132
|
+
}
|
|
1133
|
+
return value;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* The serialized schema at a source path.
|
|
1138
|
+
*
|
|
1139
|
+
* Only the schema is taken from resolution -- `accept` is not on the value, and
|
|
1140
|
+
* the value itself comes from the error. Same call `missingFileRef` in
|
|
1141
|
+
* `diagnostics.ts` makes, and it can fail the same ways (a schema that failed
|
|
1142
|
+
* to serialize, a path that no longer resolves), so failure is not an error
|
|
1143
|
+
* here, just an absence.
|
|
1144
|
+
*/
|
|
1145
|
+
function resolveSchemaAt$1(sourcePath, content) {
|
|
1146
|
+
if (!content.source || !content.schema) {
|
|
1147
|
+
return undefined;
|
|
1148
|
+
}
|
|
1149
|
+
try {
|
|
1150
|
+
const [, modulePath] = Internal.splitModuleFilePathAndModulePath(sourcePath);
|
|
1151
|
+
return Internal.resolvePath(modulePath, content.source, content.schema).schema;
|
|
1152
|
+
} catch {
|
|
1153
|
+
return undefined;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
|
|
849
1157
|
/** Marks diagnostics as ours, so a client can filter on it. */
|
|
850
1158
|
const VAL_DIAGNOSTIC_SOURCE = "val";
|
|
851
1159
|
|
|
@@ -937,7 +1245,8 @@ function createValDiagnostics({
|
|
|
937
1245
|
text,
|
|
938
1246
|
valRoot,
|
|
939
1247
|
snapshot,
|
|
940
|
-
galleryChecks
|
|
1248
|
+
galleryChecks,
|
|
1249
|
+
mediaMetadataChecks
|
|
941
1250
|
}) {
|
|
942
1251
|
if (content.errors === false) {
|
|
943
1252
|
return [];
|
|
@@ -1009,6 +1318,33 @@ function createValDiagnostics({
|
|
|
1009
1318
|
continue;
|
|
1010
1319
|
}
|
|
1011
1320
|
|
|
1321
|
+
// An unconditional media metadata placeholder: core reports
|
|
1322
|
+
// `image:check-metadata` on every `s.image()` carrying metadata, whether
|
|
1323
|
+
// or not it disagrees with the file. Show only what the adjudication
|
|
1324
|
+
// actually found, and nothing when it found nothing. Deliberately after
|
|
1325
|
+
// the missing-file branch above, so a deleted file is still reported as
|
|
1326
|
+
// `val/file-not-found` rather than as a metadata mismatch.
|
|
1327
|
+
if (isDeferredMediaMetadataCheckAt({
|
|
1328
|
+
sourcePath,
|
|
1329
|
+
error,
|
|
1330
|
+
content
|
|
1331
|
+
})) {
|
|
1332
|
+
const verdict = mediaMetadataChecks?.get(mediaMetadataCheckKey(sourcePath, error));
|
|
1333
|
+
for (const finding of verdict ?? []) {
|
|
1334
|
+
diagnostics.push(build(rangeOf(sourcePath, modulePathMap), finding.message, {
|
|
1335
|
+
code: "val/validation",
|
|
1336
|
+
sourcePath,
|
|
1337
|
+
...(finding.fixes ? {
|
|
1338
|
+
fixes: finding.fixes
|
|
1339
|
+
} : {}),
|
|
1340
|
+
...(finding.value !== undefined ? {
|
|
1341
|
+
value: finding.value
|
|
1342
|
+
} : {})
|
|
1343
|
+
}));
|
|
1344
|
+
}
|
|
1345
|
+
continue;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1012
1348
|
// A gallery-backed field whose path the gallery does not track. Core
|
|
1013
1349
|
// reports it with no fix because the remedy is elsewhere; giving it its
|
|
1014
1350
|
// own code is what lets the editor offer the two remedies.
|
|
@@ -2099,6 +2435,17 @@ async function createValCodeActions({
|
|
|
2099
2435
|
remoteHost = process.env.VAL_REMOTE_HOST || DEFAULT_VAL_REMOTE_HOST
|
|
2100
2436
|
}) {
|
|
2101
2437
|
const actions = [];
|
|
2438
|
+
/**
|
|
2439
|
+
* Fixes already offered, as `<fix target>|<fix>`.
|
|
2440
|
+
*
|
|
2441
|
+
* One problem can be reported as several diagnostics that share a fix: a
|
|
2442
|
+
* stale image reports its width and its height separately, and a gallery
|
|
2443
|
+
* check reports one finding per entry. The fix is the same patch each time --
|
|
2444
|
+
* `createFixPatch` corrects every field, and the gallery branch walks every
|
|
2445
|
+
* entry -- so without this the editor offers the identical "Val: update image
|
|
2446
|
+
* metadata" twice, and recomputes it (re-reading the image) to do so.
|
|
2447
|
+
*/
|
|
2448
|
+
const offered = new Set();
|
|
2102
2449
|
for (const diagnostic of diagnostics) {
|
|
2103
2450
|
const data = diagnostic.data;
|
|
2104
2451
|
if (!data?.fixes?.length) {
|
|
@@ -2137,6 +2484,10 @@ async function createValCodeActions({
|
|
|
2137
2484
|
if (!isLocalFix(fix)) {
|
|
2138
2485
|
continue;
|
|
2139
2486
|
}
|
|
2487
|
+
const fixTarget = data.fixSourcePath ?? data.sourcePath;
|
|
2488
|
+
if (offered.has(`${fixTarget}|${fix}`)) {
|
|
2489
|
+
continue;
|
|
2490
|
+
}
|
|
2140
2491
|
const fixEdit = await computeFixEdit({
|
|
2141
2492
|
document,
|
|
2142
2493
|
// A gallery check is reported on the entry but fixed against the record
|
|
@@ -2158,6 +2509,7 @@ async function createValCodeActions({
|
|
|
2158
2509
|
if (!fixEdit) {
|
|
2159
2510
|
continue;
|
|
2160
2511
|
}
|
|
2512
|
+
offered.add(`${fixTarget}|${fix}`);
|
|
2161
2513
|
actions.push(CodeAction.create(FIX_TITLES[fix] ?? `Val: ${fix}`,
|
|
2162
2514
|
// Not always `document.uri`: a fix inside a `.jsonValues()` entry
|
|
2163
2515
|
// edits the entry's own `*.val.json`, which is a different file from
|
|
@@ -3519,6 +3871,14 @@ function createValLanguageServer(connection) {
|
|
|
3519
3871
|
runFixHandler: args => activeProject.runFixHandler(args)
|
|
3520
3872
|
})
|
|
3521
3873
|
}) : undefined;
|
|
3874
|
+
// Core also defers "does this image's stored metadata match its file",
|
|
3875
|
+
// reporting it on every `s.image()` that carries any metadata. Same
|
|
3876
|
+
// treatment: adjudicate with the fix machinery before showing anything.
|
|
3877
|
+
const mediaMetadataChecks = result.content.errors !== false && result.content.errors.validation ? await resolveMediaMetadataChecks({
|
|
3878
|
+
validation: result.content.errors.validation,
|
|
3879
|
+
content: result.content,
|
|
3880
|
+
valRoot: activeProject.valRoot
|
|
3881
|
+
}) : undefined;
|
|
3522
3882
|
const diagnostics = createValDiagnostics({
|
|
3523
3883
|
moduleFilePath,
|
|
3524
3884
|
content: result.content,
|
|
@@ -3529,6 +3889,9 @@ function createValLanguageServer(connection) {
|
|
|
3529
3889
|
} : {}),
|
|
3530
3890
|
...(galleryChecks ? {
|
|
3531
3891
|
galleryChecks
|
|
3892
|
+
} : {}),
|
|
3893
|
+
...(mediaMetadataChecks ? {
|
|
3894
|
+
mediaMetadataChecks
|
|
3532
3895
|
} : {})
|
|
3533
3896
|
});
|
|
3534
3897
|
const unregistered = findMissingModuleDiagnostic(project.valRoot, moduleFilePath, readOpenDocument);
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"lsp",
|
|
12
12
|
"language-server"
|
|
13
13
|
],
|
|
14
|
-
"version": "0.
|
|
14
|
+
"version": "0.117.0",
|
|
15
15
|
"bin": {
|
|
16
16
|
"val-language-server": "./bin.js"
|
|
17
17
|
},
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"typescript": "^6.0.3",
|
|
30
30
|
"vscode-languageserver": "^10.1.0",
|
|
31
31
|
"vscode-languageserver-textdocument": "^1.0.14",
|
|
32
|
-
"@valbuild/core": "0.
|
|
33
|
-
"@valbuild/server": "0.
|
|
34
|
-
"@valbuild/shared": "0.
|
|
32
|
+
"@valbuild/core": "0.117.0",
|
|
33
|
+
"@valbuild/server": "0.117.0",
|
|
34
|
+
"@valbuild/shared": "0.117.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/jest": "^30.0.0",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"node": "^20.19.0 || >=22"
|
|
42
42
|
},
|
|
43
43
|
"files": [
|
|
44
|
+
"CHANGELOG.md",
|
|
44
45
|
"dist",
|
|
45
46
|
"bin.js",
|
|
46
47
|
"README.md"
|