@stacksjs/stx-vscode 0.2.544 → 0.2.546
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/dist/index.js
CHANGED
|
@@ -807,6 +807,347 @@ var DEFAULT_TRANSITION_OPTIONS = {
|
|
|
807
807
|
direction: "both" /* Both */
|
|
808
808
|
};
|
|
809
809
|
|
|
810
|
+
// ../vscode/src/language-features.ts
|
|
811
|
+
var STX_DIRECTIVES = [
|
|
812
|
+
{ name: "transition", description: "Applies transition animations to an element" },
|
|
813
|
+
{ name: "motion", description: "Controls animation display based on user preferences" },
|
|
814
|
+
{ name: "animationGroup", description: "Groups elements for coordinated animations" },
|
|
815
|
+
{ name: "scrollAnimate", description: "Triggers animation when element scrolls into view" },
|
|
816
|
+
{ name: "translate", description: "Translate a string using the i18n system" },
|
|
817
|
+
{ name: "t", description: "Short alias for translate directive" },
|
|
818
|
+
{ name: "if", description: "Conditional rendering" },
|
|
819
|
+
{ name: "else", description: "Alternative rendering for conditionals" },
|
|
820
|
+
{ name: "elseif", description: "Alternative condition for if statement" },
|
|
821
|
+
{ name: "unless", description: "Inverse conditional rendering" },
|
|
822
|
+
{ name: "foreach", description: "Iterates over an array or collection" },
|
|
823
|
+
{ name: "for", description: "Standard for loop" },
|
|
824
|
+
{ name: "while", description: "While loop" },
|
|
825
|
+
{ name: "forelse", description: "Loop with fallback when collection is empty" },
|
|
826
|
+
{ name: "switch", description: "Switch statement for multiple conditions" },
|
|
827
|
+
{ name: "case", description: "Case option in switch statement" },
|
|
828
|
+
{ name: "default", description: "Default case in switch statement" },
|
|
829
|
+
{ name: "break", description: "Break from loop or switch" },
|
|
830
|
+
{ name: "continue", description: "Continue to next iteration" },
|
|
831
|
+
{ name: "component", description: "Renders a component" },
|
|
832
|
+
{ name: "slot", description: "Define a named slot in a component" },
|
|
833
|
+
{ name: "webcomponent", description: "Include a web component" },
|
|
834
|
+
{ name: "ts", description: "TypeScript code block" },
|
|
835
|
+
{ name: "js", description: "JavaScript code block" },
|
|
836
|
+
{ name: "script", description: "Script code block (alternative to @ts)" },
|
|
837
|
+
{ name: "css", description: "CSS code block" },
|
|
838
|
+
{ name: "json", description: "Output variable as JSON" },
|
|
839
|
+
{ name: "markdown", description: "Markdown content block" },
|
|
840
|
+
{ name: "raw", description: "Display content without processing expressions" },
|
|
841
|
+
{ name: "verbatim", description: "Display content without processing directives" },
|
|
842
|
+
{ name: "extends", description: "Extend a base layout" },
|
|
843
|
+
{ name: "section", description: "Define a content section" },
|
|
844
|
+
{ name: "yield", description: "Output the contents of a section" },
|
|
845
|
+
{ name: "parent", description: "Include parent section content" },
|
|
846
|
+
{ name: "stack", description: "Define a stack for pushing content" },
|
|
847
|
+
{ name: "push", description: "Push content to a stack" },
|
|
848
|
+
{ name: "pushIf", description: "Conditionally push content to a stack" },
|
|
849
|
+
{ name: "pushOnce", description: "Push content to a stack only once" },
|
|
850
|
+
{ name: "prepend", description: "Prepend content to a stack" },
|
|
851
|
+
{ name: "prependOnce", description: "Prepend content to a stack only once" },
|
|
852
|
+
{ name: "include", description: "Include another template file" },
|
|
853
|
+
{ name: "includeIf", description: "Conditionally include a template" },
|
|
854
|
+
{ name: "includeWhen", description: "Include template when condition is true" },
|
|
855
|
+
{ name: "includeUnless", description: "Include template unless condition is true" },
|
|
856
|
+
{ name: "includeFirst", description: "Include the first existing template from a list" },
|
|
857
|
+
{ name: "auth", description: "Content visible only to authenticated users" },
|
|
858
|
+
{ name: "guest", description: "Content visible only to guests" },
|
|
859
|
+
{ name: "can", description: "Check if user has permission" },
|
|
860
|
+
{ name: "cannot", description: "Check if user lacks permission" },
|
|
861
|
+
{ name: "elsecan", description: "Try another permission when the preceding authorization check fails" },
|
|
862
|
+
{ name: "elsecannot", description: "Try another denied permission when the preceding authorization check fails" },
|
|
863
|
+
{ name: "env", description: "Check environment condition" },
|
|
864
|
+
{ name: "isset", description: "Check if a variable is set" },
|
|
865
|
+
{ name: "empty", description: "Check if a variable is empty" },
|
|
866
|
+
{ name: "error", description: "Display validation error for a field" },
|
|
867
|
+
{ name: "hasSection", description: "Check if a section exists" },
|
|
868
|
+
{ name: "once", description: "Include content only once per rendering cycle" },
|
|
869
|
+
{ name: "use", description: "Import a class or namespace" },
|
|
870
|
+
{ name: "csrf", description: "Include CSRF protection token" },
|
|
871
|
+
{ name: "method", description: "Specify form submission method" },
|
|
872
|
+
{ name: "locale", description: "Set locale for content" },
|
|
873
|
+
{ name: "errorBoundary", description: "Catch rendering errors and show fallback content", snippet: `@errorBoundary
|
|
874
|
+
\${1}
|
|
875
|
+
@fallback
|
|
876
|
+
\${2}
|
|
877
|
+
@enderrorBoundary` },
|
|
878
|
+
{ name: "fallback", description: "Define fallback content for an error, suspense, or stream boundary" },
|
|
879
|
+
{ name: "suspense", description: "Coordinate async rendering with fallback content", snippet: `@suspense
|
|
880
|
+
\${1}
|
|
881
|
+
@fallback
|
|
882
|
+
\${2}
|
|
883
|
+
@endsuspense` },
|
|
884
|
+
{ name: "async", description: "Load and render a component asynchronously", snippet: "@async(component: '${1:Component}', timeout: ${2:5000})\n\t${3}\n@endasync" },
|
|
885
|
+
{ name: "defer", description: "Defer rendering until a browser trigger fires", snippet: "@defer(on: '${1:visible}')\n\t${2}\n@enddefer" },
|
|
886
|
+
{ name: "teleport", description: "Render content into another DOM container", snippet: "@teleport('${1:#modals}')\n\t${2}\n@endteleport" },
|
|
887
|
+
{ name: "keepAlive", description: "Preserve component state while it is inactive", snippet: `@keepAlive
|
|
888
|
+
\${1}
|
|
889
|
+
@endkeepAlive` },
|
|
890
|
+
{ name: "virtualList", description: "Efficiently render a large scrolling list", snippet: "@virtualList(${1:items}, { itemHeight: ${2:50}, containerHeight: ${3:400} })\n\t${4}\n@endvirtualList" },
|
|
891
|
+
{ name: "virtualGrid", description: "Efficiently render a large scrolling grid", snippet: "@virtualGrid(${1:items}, { columns: ${2:4}, rowHeight: ${3:200}, containerHeight: ${4:600} })\n\t${5}\n@endvirtualGrid" },
|
|
892
|
+
{ name: "infiniteList", description: "Render a virtual list that loads additional items", snippet: "@infiniteList(${1:items}, { itemHeight: ${2:50} })\n\t${3}\n@loading\n\t${4}\n@endinfiniteList" },
|
|
893
|
+
{ name: "loading", description: "Define loading content for an infinite list" },
|
|
894
|
+
{ name: "stream", description: "Stream a server-rendered boundary independently", snippet: `@stream('\${1:content}')
|
|
895
|
+
\${2}
|
|
896
|
+
@fallback
|
|
897
|
+
\${3}
|
|
898
|
+
@endstream` },
|
|
899
|
+
{ name: "memo", description: "Skip subtree updates while dependencies are unchanged", snippet: "@memo([${1:dependencies}])\n\t${2}\n@endmemo" },
|
|
900
|
+
{ name: "client:load", description: "Hydrate an island immediately on page load", snippet: `@client:load
|
|
901
|
+
\${1}
|
|
902
|
+
@endclient` },
|
|
903
|
+
{ name: "client:idle", description: "Hydrate an island when the browser is idle", snippet: `@client:idle
|
|
904
|
+
\${1}
|
|
905
|
+
@endclient` },
|
|
906
|
+
{ name: "client:visible", description: "Hydrate an island when it enters the viewport", snippet: `@client:visible
|
|
907
|
+
\${1}
|
|
908
|
+
@endclient` },
|
|
909
|
+
{ name: "client:media", description: "Hydrate an island when a media query matches", snippet: "@client:media(media: '${1:(min-width: 768px)}')\n\t${2}\n@endclient" },
|
|
910
|
+
{ name: "client:only", description: "Render an island only in the browser", snippet: `@client:only
|
|
911
|
+
\${1}
|
|
912
|
+
@endclient` },
|
|
913
|
+
{ name: "client:hover", description: "Hydrate an island on its first hover or focus", snippet: `@client:hover
|
|
914
|
+
\${1}
|
|
915
|
+
@endclient` },
|
|
916
|
+
{ name: "client:event", description: "Hydrate an island when a custom event fires", snippet: "@client:event(event: '${1:event-name}')\n\t${2}\n@endclient" },
|
|
917
|
+
{ name: "static", description: "Render content without a hydration wrapper", snippet: `@static
|
|
918
|
+
\${1}
|
|
919
|
+
@endstatic` },
|
|
920
|
+
{ name: "computed", description: "Declare a computed template value", snippet: "@computed(${1:name}, ${2:expression})" },
|
|
921
|
+
{ name: "watch", description: "Watch a value and run a handler when it changes", snippet: "@watch(${1:source})\n\t${2}\n@endwatch" },
|
|
922
|
+
{ name: "errors", description: "Render all validation errors for a field", snippet: "@errors(${1:form.field})\n\t${2}\n@enderrors" },
|
|
923
|
+
{ name: "hasErrors", description: "Conditionally render when a field has validation errors", snippet: "@hasErrors(${1:form.field})\n\t${2}\n@endhasErrors" },
|
|
924
|
+
{ name: "head", description: "Add markup to the document head", snippet: `@head
|
|
925
|
+
\${1}
|
|
926
|
+
@endhead` },
|
|
927
|
+
{ name: "title", description: "Set the document title", snippet: "@title('${1:Page title}')" },
|
|
928
|
+
{ name: "meta", description: "Add a metadata tag", snippet: "@meta('${1:description}', '${2:content}')" },
|
|
929
|
+
{ name: "metaTag", description: "Add a metadata tag with full attribute control", snippet: "@metaTag({ name: '${1:description}', content: '${2:content}' })" },
|
|
930
|
+
{ name: "seo", description: "Generate title, meta, Open Graph, and Twitter tags", snippet: "@seo({ title: ${1:title}, description: ${2:description} })" },
|
|
931
|
+
{ name: "structuredData", description: "Emit JSON-LD structured data", snippet: "@structuredData(${1:schema})" },
|
|
932
|
+
{ name: "csp", description: "Emit a Content Security Policy meta tag", snippet: "@csp" },
|
|
933
|
+
{ name: "cspNonce", description: "Output the current Content Security Policy nonce", snippet: "@cspNonce" },
|
|
934
|
+
{ name: "endtransition", description: "Ends a transition block" },
|
|
935
|
+
{ name: "endmotion", description: "Ends a motion block" },
|
|
936
|
+
{ name: "endscrollAnimate", description: "Ends a scroll animation block" },
|
|
937
|
+
{ name: "endif", description: "Ends an if block" },
|
|
938
|
+
{ name: "endunless", description: "Ends an unless block" },
|
|
939
|
+
{ name: "endfor", description: "Ends a for loop block" },
|
|
940
|
+
{ name: "endforeach", description: "Ends a foreach loop block" },
|
|
941
|
+
{ name: "endforelse", description: "Ends a forelse block" },
|
|
942
|
+
{ name: "endwhile", description: "Ends a while block" },
|
|
943
|
+
{ name: "endswitch", description: "Ends a switch block" },
|
|
944
|
+
{ name: "endts", description: "Ends a TypeScript code block" },
|
|
945
|
+
{ name: "endjs", description: "Ends a JavaScript code block" },
|
|
946
|
+
{ name: "endscript", description: "Ends a script block" },
|
|
947
|
+
{ name: "endcss", description: "Ends a CSS block" },
|
|
948
|
+
{ name: "endmarkdown", description: "Ends a markdown block" },
|
|
949
|
+
{ name: "endraw", description: "Ends a raw content block" },
|
|
950
|
+
{ name: "endverbatim", description: "Ends a verbatim block" },
|
|
951
|
+
{ name: "endcomponent", description: "Ends a component block" },
|
|
952
|
+
{ name: "endslot", description: "Ends a slot block" },
|
|
953
|
+
{ name: "endsection", description: "Ends a section block" },
|
|
954
|
+
{ name: "endpush", description: "Ends a push block" },
|
|
955
|
+
{ name: "endpushIf", description: "Ends a pushIf block" },
|
|
956
|
+
{ name: "endpushOnce", description: "Ends a pushOnce block" },
|
|
957
|
+
{ name: "endprepend", description: "Ends a prepend block" },
|
|
958
|
+
{ name: "endprependOnce", description: "Ends a prependOnce block" },
|
|
959
|
+
{ name: "endauth", description: "Ends an auth block" },
|
|
960
|
+
{ name: "endguest", description: "Ends a guest block" },
|
|
961
|
+
{ name: "endcan", description: "Ends a can block" },
|
|
962
|
+
{ name: "endcannot", description: "Ends a cannot block" },
|
|
963
|
+
{ name: "endempty", description: "Ends an empty block" },
|
|
964
|
+
{ name: "endenv", description: "Ends an env block" },
|
|
965
|
+
{ name: "endisset", description: "Ends an isset block" },
|
|
966
|
+
{ name: "enderror", description: "Ends an error block" },
|
|
967
|
+
{ name: "endonce", description: "Ends a once block" },
|
|
968
|
+
{ name: "endwebcomponent", description: "Ends a webcomponent block" },
|
|
969
|
+
{ name: "enderrorBoundary", description: "Ends an error boundary" },
|
|
970
|
+
{ name: "endsuspense", description: "Ends a suspense boundary" },
|
|
971
|
+
{ name: "endasync", description: "Ends an async component block" },
|
|
972
|
+
{ name: "enddefer", description: "Ends a deferred block" },
|
|
973
|
+
{ name: "endteleport", description: "Ends a teleported block" },
|
|
974
|
+
{ name: "endkeepAlive", description: "Ends a keep-alive block" },
|
|
975
|
+
{ name: "endvirtualList", description: "Ends a virtual list" },
|
|
976
|
+
{ name: "endvirtualGrid", description: "Ends a virtual grid" },
|
|
977
|
+
{ name: "endinfiniteList", description: "Ends an infinite list" },
|
|
978
|
+
{ name: "endstream", description: "Ends a streamed boundary" },
|
|
979
|
+
{ name: "endmemo", description: "Ends a memoized block" },
|
|
980
|
+
{ name: "endclient", description: "Ends a partially hydrated island" },
|
|
981
|
+
{ name: "endstatic", description: "Ends a static block" },
|
|
982
|
+
{ name: "endwatch", description: "Ends a watch block" },
|
|
983
|
+
{ name: "enderrors", description: "Ends a validation errors block" },
|
|
984
|
+
{ name: "endhasErrors", description: "Ends a validation condition" },
|
|
985
|
+
{ name: "endhead", description: "Ends a document head block" }
|
|
986
|
+
];
|
|
987
|
+
var STX_DIRECTIVE_PAIRS = {
|
|
988
|
+
if: "endif",
|
|
989
|
+
unless: "endunless",
|
|
990
|
+
for: "endfor",
|
|
991
|
+
foreach: "endforeach",
|
|
992
|
+
forelse: "endforelse",
|
|
993
|
+
while: "endwhile",
|
|
994
|
+
switch: "endswitch",
|
|
995
|
+
ts: "endts",
|
|
996
|
+
js: "endjs",
|
|
997
|
+
script: "endscript",
|
|
998
|
+
css: "endcss",
|
|
999
|
+
markdown: "endmarkdown",
|
|
1000
|
+
raw: "endraw",
|
|
1001
|
+
verbatim: "endverbatim",
|
|
1002
|
+
component: "endcomponent",
|
|
1003
|
+
slot: "endslot",
|
|
1004
|
+
webcomponent: "endwebcomponent",
|
|
1005
|
+
section: "endsection",
|
|
1006
|
+
push: "endpush",
|
|
1007
|
+
pushIf: "endpushIf",
|
|
1008
|
+
pushOnce: "endpushOnce",
|
|
1009
|
+
prepend: "endprepend",
|
|
1010
|
+
prependOnce: "endprependOnce",
|
|
1011
|
+
auth: "endauth",
|
|
1012
|
+
guest: "endguest",
|
|
1013
|
+
can: "endcan",
|
|
1014
|
+
cannot: "endcannot",
|
|
1015
|
+
env: "endenv",
|
|
1016
|
+
isset: "endisset",
|
|
1017
|
+
empty: "endempty",
|
|
1018
|
+
error: "enderror",
|
|
1019
|
+
once: "endonce",
|
|
1020
|
+
transition: "endtransition",
|
|
1021
|
+
motion: "endmotion",
|
|
1022
|
+
scrollAnimate: "endscrollAnimate",
|
|
1023
|
+
errorBoundary: "enderrorBoundary",
|
|
1024
|
+
suspense: "endsuspense",
|
|
1025
|
+
async: "endasync",
|
|
1026
|
+
defer: "enddefer",
|
|
1027
|
+
teleport: "endteleport",
|
|
1028
|
+
keepAlive: "endkeepAlive",
|
|
1029
|
+
virtualList: "endvirtualList",
|
|
1030
|
+
virtualGrid: "endvirtualGrid",
|
|
1031
|
+
infiniteList: "endinfiniteList",
|
|
1032
|
+
stream: "endstream",
|
|
1033
|
+
memo: "endmemo",
|
|
1034
|
+
static: "endstatic",
|
|
1035
|
+
watch: "endwatch",
|
|
1036
|
+
errors: "enderrors",
|
|
1037
|
+
hasErrors: "endhasErrors",
|
|
1038
|
+
head: "endhead"
|
|
1039
|
+
};
|
|
1040
|
+
var STX_OPENING_DIRECTIVE_BY_CLOSE = new Map(Object.entries(STX_DIRECTIVE_PAIRS).map(([opening, closing]) => [closing, opening]));
|
|
1041
|
+
var STX_DIRECTIVE_BY_NAME = new Map(STX_DIRECTIVES.map((directive) => [directive.name.toLowerCase(), directive]));
|
|
1042
|
+
function getStxDirectiveAtOffset(line, offset) {
|
|
1043
|
+
const directivePattern = /@([A-Za-z][\w:]*)/g;
|
|
1044
|
+
let match;
|
|
1045
|
+
while ((match = directivePattern.exec(line)) !== null) {
|
|
1046
|
+
const start = match.index;
|
|
1047
|
+
const end = start + match[0].length;
|
|
1048
|
+
if (offset >= start && offset <= end)
|
|
1049
|
+
return { name: match[1], start, end };
|
|
1050
|
+
}
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
var STX_ATTRIBUTE_DIRECTIVES = [
|
|
1054
|
+
{ name: ":if", description: "Conditionally render this element", snippet: ':if="${1:condition}"' },
|
|
1055
|
+
{ name: ":else-if", description: "Render when the preceding condition is false and this condition is true", snippet: ':else-if="${1:condition}"' },
|
|
1056
|
+
{ name: ":else", description: "Render when the preceding conditions are false", snippet: ":else" },
|
|
1057
|
+
{ name: ":for", description: "Render this element for every item in a reactive collection", snippet: ':for="${1:item} in ${2:items}"' },
|
|
1058
|
+
{ name: ":show", description: "Toggle this element without removing it from the DOM", snippet: ':show="${1:condition}"' },
|
|
1059
|
+
{ name: ":key", description: "Provide a stable identity for a rendered item", snippet: ':key="${1:item.id}"' },
|
|
1060
|
+
{ name: "v-if", description: "Vue-compatible alias for :if", snippet: 'v-if="${1:condition}"' },
|
|
1061
|
+
{ name: "v-else-if", description: "Vue-compatible alias for :else-if", snippet: 'v-else-if="${1:condition}"' },
|
|
1062
|
+
{ name: "v-else", description: "Vue-compatible alias for :else", snippet: "v-else" },
|
|
1063
|
+
{ name: "v-memo", description: "Skip subtree updates while dependencies are unchanged", snippet: 'v-memo="[${1:dependencies}]"' },
|
|
1064
|
+
{ name: "x-if", description: "Alpine-compatible alias for :if", snippet: 'x-if="${1:condition}"' },
|
|
1065
|
+
{ name: "x-else-if", description: "Alpine-compatible alias for :else-if", snippet: 'x-else-if="${1:condition}"' },
|
|
1066
|
+
{ name: "x-else", description: "Alpine-compatible alias for :else", snippet: "x-else" },
|
|
1067
|
+
{ name: "x-for", description: "Alpine-compatible alias for :for", snippet: 'x-for="${1:item} in ${2:items}"' },
|
|
1068
|
+
{ name: "x-show", description: "Alpine-compatible alias for :show", snippet: 'x-show="${1:condition}"' },
|
|
1069
|
+
{ name: "x-text", description: "Set text content from a reactive expression", snippet: 'x-text="${1:expression}"' },
|
|
1070
|
+
{ name: "x-html", description: "Set HTML content from a reactive expression", snippet: 'x-html="${1:expression}"' },
|
|
1071
|
+
{ name: "x-model", description: "Two-way bind a form control to reactive state", snippet: 'x-model="${1:value}"' },
|
|
1072
|
+
{ name: "x-class", description: "Bind classes from a reactive expression", snippet: 'x-class="${1:classes}"' },
|
|
1073
|
+
{ name: "x-style", description: "Bind inline styles from a reactive expression", snippet: 'x-style="${1:styles}"' },
|
|
1074
|
+
{ name: "x-href", description: "Bind an anchor destination", snippet: 'x-href="${1:url}"' },
|
|
1075
|
+
{ name: "x-src", description: "Bind an image or media source", snippet: 'x-src="${1:url}"' },
|
|
1076
|
+
{ name: "x-bind:", description: "Bind any HTML attribute", snippet: 'x-bind:${1:attribute}="${2:expression}"' },
|
|
1077
|
+
{ name: "x-ref", description: "Register a named element reference", snippet: 'x-ref="${1:name}"' },
|
|
1078
|
+
{ name: "x-cloak", description: "Hide an element until its reactive scope is ready", snippet: "x-cloak" },
|
|
1079
|
+
{ name: "@click", description: "Run an expression when the element is clicked", snippet: '@click="${1:handler}"' },
|
|
1080
|
+
{ name: "@submit", description: "Run an expression when the form is submitted", snippet: '@submit.prevent="${1:handler}"' },
|
|
1081
|
+
{ name: "@input", description: "Run an expression when input is received", snippet: '@input="${1:handler}"' },
|
|
1082
|
+
{ name: "@change", description: "Run an expression when the value changes", snippet: '@change="${1:handler}"' },
|
|
1083
|
+
{ name: "@keydown", description: "Run an expression on keydown", snippet: '@keydown="${1:handler}"' },
|
|
1084
|
+
{ name: "@keyup", description: "Run an expression on keyup", snippet: '@keyup="${1:handler}"' },
|
|
1085
|
+
{ name: "@focus", description: "Run an expression when the element receives focus", snippet: '@focus="${1:handler}"' },
|
|
1086
|
+
{ name: "@blur", description: "Run an expression when the element loses focus", snippet: '@blur="${1:handler}"' },
|
|
1087
|
+
{ name: "@mouseenter", description: "Run an expression when the pointer enters the element", snippet: '@mouseenter="${1:handler}"' },
|
|
1088
|
+
{ name: "@mouseleave", description: "Run an expression when the pointer leaves the element", snippet: '@mouseleave="${1:handler}"' },
|
|
1089
|
+
{ name: "stx-hydrate", description: "Defer reactive hydration until a trigger fires", snippet: 'stx-hydrate="${1:visible}"' }
|
|
1090
|
+
];
|
|
1091
|
+
var STX_ATTRIBUTE_DIRECTIVE_BY_NAME = new Map(STX_ATTRIBUTE_DIRECTIVES.map((directive) => [directive.name.toLowerCase(), directive]));
|
|
1092
|
+
function getStxAttributeCompletionContext(sourceBeforeCursor) {
|
|
1093
|
+
let tagStart = -1;
|
|
1094
|
+
let quote;
|
|
1095
|
+
for (let index = 0;index < sourceBeforeCursor.length; index++) {
|
|
1096
|
+
const character = sourceBeforeCursor[index];
|
|
1097
|
+
if (quote) {
|
|
1098
|
+
if (character === quote && sourceBeforeCursor[index - 1] !== "\\")
|
|
1099
|
+
quote = undefined;
|
|
1100
|
+
continue;
|
|
1101
|
+
}
|
|
1102
|
+
if ((character === '"' || character === "'") && tagStart >= 0) {
|
|
1103
|
+
quote = character;
|
|
1104
|
+
continue;
|
|
1105
|
+
}
|
|
1106
|
+
if (character === "<") {
|
|
1107
|
+
const next = sourceBeforeCursor[index + 1];
|
|
1108
|
+
tagStart = next && /[A-Za-z]/.test(next) ? index : -1;
|
|
1109
|
+
} else if (character === ">") {
|
|
1110
|
+
tagStart = -1;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
if (tagStart < 0 || quote)
|
|
1114
|
+
return;
|
|
1115
|
+
const tag = sourceBeforeCursor.slice(tagStart + 1);
|
|
1116
|
+
const match = tag.match(/\s([:@\w.-]*)$/);
|
|
1117
|
+
if (!match)
|
|
1118
|
+
return;
|
|
1119
|
+
return { prefix: match[1] };
|
|
1120
|
+
}
|
|
1121
|
+
function getStxAttributeAtOffset(source, offset) {
|
|
1122
|
+
const attributePattern = /(?:^|\s)([:@][A-Za-z][\w:.-]*|(?:x|v|stx)-[A-Za-z][\w:.-]*)/g;
|
|
1123
|
+
let match;
|
|
1124
|
+
while ((match = attributePattern.exec(source)) !== null) {
|
|
1125
|
+
const name = match[1];
|
|
1126
|
+
const start = match.index + match[0].length - name.length;
|
|
1127
|
+
const end = start + name.length;
|
|
1128
|
+
if (offset < start || offset > end)
|
|
1129
|
+
continue;
|
|
1130
|
+
const completionContext = getStxAttributeCompletionContext(source.slice(0, end));
|
|
1131
|
+
if (completionContext?.prefix === name)
|
|
1132
|
+
return { name, start, end };
|
|
1133
|
+
}
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
function getStxAttributeDefinition(name) {
|
|
1137
|
+
const normalized = name.toLowerCase();
|
|
1138
|
+
const exact = STX_ATTRIBUTE_DIRECTIVE_BY_NAME.get(normalized);
|
|
1139
|
+
if (exact)
|
|
1140
|
+
return exact;
|
|
1141
|
+
if (normalized.startsWith("@"))
|
|
1142
|
+
return STX_ATTRIBUTE_DIRECTIVE_BY_NAME.get(normalized.split(".")[0]);
|
|
1143
|
+
if (normalized.startsWith("x-bind:"))
|
|
1144
|
+
return STX_ATTRIBUTE_DIRECTIVE_BY_NAME.get("x-bind:");
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
function stxSnippetPreview(snippet) {
|
|
1148
|
+
return snippet.replace(/\$\{\d+\|([^|]+)\|\}/g, (_match, choices) => choices.split(",")[0].replace(/\\,/g, ",")).replace(/\$\{\d+:([^}]*)\}/g, "$1").replace(/\$\{\d+\}/g, "").replace(/\$\d+/g, "");
|
|
1149
|
+
}
|
|
1150
|
+
|
|
810
1151
|
// ../vscode/src/services/ComponentRegistry.ts
|
|
811
1152
|
import * as vscode from "vscode";
|
|
812
1153
|
import * as path from "node:path";
|
|
@@ -1388,6 +1729,111 @@ ${formattedCode}
|
|
|
1388
1729
|
`);
|
|
1389
1730
|
}
|
|
1390
1731
|
|
|
1732
|
+
// ../vscode/src/providers/hover-documentation.ts
|
|
1733
|
+
var JAVASCRIPT_OPERATOR_HOVERS = {
|
|
1734
|
+
typeof: {
|
|
1735
|
+
syntax: "typeof operand",
|
|
1736
|
+
description: '**JavaScript Operator**\n\nReturns a string indicating the type of the operand.\n\n**Possible return values:**\n- `"string"` - for string values\n- `"number"` - for number values\n- `"boolean"` - for boolean values\n- `"object"` - for objects and null\n- `"function"` - for functions\n- `"undefined"` - for undefined\n- `"symbol"` - for symbols\n- `"bigint"` - for BigInt values'
|
|
1737
|
+
},
|
|
1738
|
+
instanceof: {
|
|
1739
|
+
syntax: "object instanceof Constructor",
|
|
1740
|
+
description: "**JavaScript Operator**\n\nTests whether an object has in its prototype chain the prototype property of a constructor. Returns `true` or `false`."
|
|
1741
|
+
},
|
|
1742
|
+
delete: {
|
|
1743
|
+
syntax: "delete object.property",
|
|
1744
|
+
description: "**JavaScript Operator**\n\nRemoves a property from an object. Returns `true` if successful."
|
|
1745
|
+
},
|
|
1746
|
+
in: {
|
|
1747
|
+
syntax: '"property" in object',
|
|
1748
|
+
description: "**JavaScript Operator**\n\nReturns `true` if the specified property is in the specified object or its prototype chain."
|
|
1749
|
+
},
|
|
1750
|
+
of: {
|
|
1751
|
+
syntax: "for (const item of iterable)",
|
|
1752
|
+
description: "**JavaScript Keyword**\n\nUsed in `for...of` loops to iterate over iterable objects (Arrays, Strings, Maps, Sets, etc.)."
|
|
1753
|
+
}
|
|
1754
|
+
};
|
|
1755
|
+
var GLOBAL_OBJECT_HOVERS = {
|
|
1756
|
+
window: { type: "Window & typeof globalThis", description: "The global window object represents the browser window. Provides access to the DOM, browser APIs, and global variables." },
|
|
1757
|
+
document: { type: "Document", description: "The Document interface represents the web page loaded in the browser. Entry point to the DOM tree." },
|
|
1758
|
+
console: { type: "Console", description: "Provides access to the browser's debugging console with methods like `log()`, `error()`, `warn()`, etc." },
|
|
1759
|
+
navigator: { type: "Navigator", description: "Represents the state and identity of the user agent (browser). Provides information about the browser and device." },
|
|
1760
|
+
location: { type: "Location", description: "Represents the URL of the current document and provides methods to manipulate the browser's location." },
|
|
1761
|
+
localStorage: { type: "Storage", description: "Provides access to the browser's local storage. Data persists even after the browser is closed." },
|
|
1762
|
+
sessionStorage: { type: "Storage", description: "Provides access to the browser's session storage. Data is cleared when the page session ends." },
|
|
1763
|
+
history: { type: "History", description: "Provides an interface for manipulating the browser session history (pages visited in the tab/frame)." },
|
|
1764
|
+
Math: { type: "Math", description: "Built-in object with properties and methods for mathematical constants and functions." },
|
|
1765
|
+
JSON: { type: "JSON", description: "Provides methods for parsing JSON and converting values to JSON: `parse()` and `stringify()`." },
|
|
1766
|
+
globalThis: { type: "typeof globalThis", description: "Provides a standard way to access the global object across different JavaScript environments." }
|
|
1767
|
+
};
|
|
1768
|
+
var HTML_TAGS = new Set([
|
|
1769
|
+
"div",
|
|
1770
|
+
"span",
|
|
1771
|
+
"p",
|
|
1772
|
+
"h1",
|
|
1773
|
+
"h2",
|
|
1774
|
+
"h3",
|
|
1775
|
+
"h4",
|
|
1776
|
+
"h5",
|
|
1777
|
+
"h6",
|
|
1778
|
+
"strong",
|
|
1779
|
+
"em",
|
|
1780
|
+
"a",
|
|
1781
|
+
"img",
|
|
1782
|
+
"button",
|
|
1783
|
+
"input",
|
|
1784
|
+
"form",
|
|
1785
|
+
"label",
|
|
1786
|
+
"ul",
|
|
1787
|
+
"ol",
|
|
1788
|
+
"li",
|
|
1789
|
+
"table",
|
|
1790
|
+
"tr",
|
|
1791
|
+
"td",
|
|
1792
|
+
"th",
|
|
1793
|
+
"thead",
|
|
1794
|
+
"tbody",
|
|
1795
|
+
"select",
|
|
1796
|
+
"option",
|
|
1797
|
+
"textarea",
|
|
1798
|
+
"header",
|
|
1799
|
+
"footer",
|
|
1800
|
+
"nav",
|
|
1801
|
+
"main",
|
|
1802
|
+
"body",
|
|
1803
|
+
"section",
|
|
1804
|
+
"article",
|
|
1805
|
+
"aside",
|
|
1806
|
+
"code",
|
|
1807
|
+
"pre",
|
|
1808
|
+
"hr",
|
|
1809
|
+
"br"
|
|
1810
|
+
]);
|
|
1811
|
+
var HTML_TAG_DESCRIPTIONS = {
|
|
1812
|
+
body: "Main content of the HTML document. Contains all content that is visible to the user.",
|
|
1813
|
+
div: "Generic container element for flow content with no semantic meaning.",
|
|
1814
|
+
span: "Generic inline container with no semantic meaning. Used for styling or grouping text.",
|
|
1815
|
+
p: "Paragraph element representing a block of text.",
|
|
1816
|
+
strong: "Indicates strong importance. Text is typically displayed in bold.",
|
|
1817
|
+
em: "Marks text that has stress emphasis. Text is typically displayed in italic.",
|
|
1818
|
+
a: "Anchor element for creating hyperlinks to other pages, files, or locations.",
|
|
1819
|
+
img: "Embeds an image into the document. Self-closing tag requiring src attribute.",
|
|
1820
|
+
button: "Clickable button element for forms or interactive elements.",
|
|
1821
|
+
input: "Form input element for user data entry. Requires type attribute.",
|
|
1822
|
+
form: "Container for a form with inputs and controls for user submission.",
|
|
1823
|
+
ul: "Unordered list container. Contains li elements.",
|
|
1824
|
+
ol: "Ordered (numbered) list container. Contains li elements.",
|
|
1825
|
+
li: "List item element. Used within ul or ol containers.",
|
|
1826
|
+
table: "Container for tabular data with rows and columns.",
|
|
1827
|
+
pre: "Preformatted text element. Preserves whitespace and line breaks.",
|
|
1828
|
+
code: "Represents computer code within a document.",
|
|
1829
|
+
label: "Label for a form element. Improves accessibility and usability."
|
|
1830
|
+
};
|
|
1831
|
+
function htmlTagDescription(tag) {
|
|
1832
|
+
if (/^h[1-6]$/.test(tag))
|
|
1833
|
+
return `Level ${tag.slice(1)} heading element. H1 is most important, H6 is least important.`;
|
|
1834
|
+
return HTML_TAG_DESCRIPTIONS[tag] ?? `HTML ${tag} element`;
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1391
1837
|
// ../vscode/src/providers/hoverProvider.ts
|
|
1392
1838
|
function appendDiagnosticInfo(hover, document, position) {
|
|
1393
1839
|
const diagnostics = vscode2.languages.getDiagnostics(document.uri);
|
|
@@ -1442,6 +1888,23 @@ function createHoverProvider(virtualTsDocumentProvider) {
|
|
|
1442
1888
|
return null;
|
|
1443
1889
|
}
|
|
1444
1890
|
const word = document.getText(wordRange);
|
|
1891
|
+
const source = document.getText();
|
|
1892
|
+
const sourceOffset = document.offsetAt(position);
|
|
1893
|
+
const attributeContext = getStxAttributeAtOffset(source, sourceOffset);
|
|
1894
|
+
if (attributeContext) {
|
|
1895
|
+
const definition = getStxAttributeDefinition(attributeContext.name);
|
|
1896
|
+
if (definition) {
|
|
1897
|
+
const hover = new vscode2.MarkdownString;
|
|
1898
|
+
hover.appendMarkdown(definition.description);
|
|
1899
|
+
hover.appendMarkdown(`
|
|
1900
|
+
|
|
1901
|
+
**Syntax**
|
|
1902
|
+
`);
|
|
1903
|
+
hover.appendCodeblock(stxSnippetPreview(definition.snippet), "stx");
|
|
1904
|
+
const range = new vscode2.Range(document.positionAt(attributeContext.start), document.positionAt(attributeContext.end));
|
|
1905
|
+
return createHoverWithDiagnostics(hover, document, position, range);
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1445
1908
|
const line = document.lineAt(position.line).text;
|
|
1446
1909
|
const textBeforeWord = document.getText(new vscode2.Range(new vscode2.Position(position.line, 0), wordRange.start));
|
|
1447
1910
|
const propertyAccessMatch = textBeforeWord.match(/(\w+)\.$/);
|
|
@@ -1520,100 +1983,20 @@ ${propDetail.description}`);
|
|
|
1520
1983
|
}
|
|
1521
1984
|
}
|
|
1522
1985
|
}
|
|
1523
|
-
const
|
|
1524
|
-
if (
|
|
1986
|
+
const operatorDocumentation = JAVASCRIPT_OPERATOR_HOVERS[word];
|
|
1987
|
+
if (operatorDocumentation) {
|
|
1525
1988
|
const hover = new vscode2.MarkdownString;
|
|
1526
1989
|
hover.isTrusted = true;
|
|
1527
1990
|
hover.supportHtml = true;
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
case "typeof":
|
|
1531
|
-
hover.appendCodeblock("typeof operand", "typescript");
|
|
1532
|
-
hover.appendText(`
|
|
1533
|
-
|
|
1534
|
-
`);
|
|
1535
|
-
description = '**JavaScript Operator**\n\nReturns a string indicating the type of the operand.\n\n**Possible return values:**\n- `"string"` - for string values\n- `"number"` - for number values\n- `"boolean"` - for boolean values\n- `"object"` - for objects and null\n- `"function"` - for functions\n- `"undefined"` - for undefined\n- `"symbol"` - for symbols\n- `"bigint"` - for BigInt values';
|
|
1536
|
-
break;
|
|
1537
|
-
case "instanceof":
|
|
1538
|
-
hover.appendCodeblock("object instanceof Constructor", "typescript");
|
|
1539
|
-
hover.appendText(`
|
|
1540
|
-
|
|
1541
|
-
`);
|
|
1542
|
-
description = "**JavaScript Operator**\n\nTests whether an object has in its prototype chain the prototype property of a constructor. Returns `true` or `false`.";
|
|
1543
|
-
break;
|
|
1544
|
-
case "delete":
|
|
1545
|
-
hover.appendCodeblock("delete object.property", "typescript");
|
|
1546
|
-
hover.appendText(`
|
|
1547
|
-
|
|
1548
|
-
`);
|
|
1549
|
-
description = "**JavaScript Operator**\n\nRemoves a property from an object. Returns `true` if successful.";
|
|
1550
|
-
break;
|
|
1551
|
-
case "in":
|
|
1552
|
-
hover.appendCodeblock('"property" in object', "typescript");
|
|
1553
|
-
hover.appendText(`
|
|
1554
|
-
|
|
1555
|
-
`);
|
|
1556
|
-
description = "**JavaScript Operator**\n\nReturns `true` if the specified property is in the specified object or its prototype chain.";
|
|
1557
|
-
break;
|
|
1558
|
-
case "of":
|
|
1559
|
-
hover.appendCodeblock("for (const item of iterable)", "typescript");
|
|
1560
|
-
hover.appendText(`
|
|
1991
|
+
hover.appendCodeblock(operatorDocumentation.syntax, "typescript");
|
|
1992
|
+
hover.appendText(`
|
|
1561
1993
|
|
|
1562
1994
|
`);
|
|
1563
|
-
|
|
1564
|
-
break;
|
|
1565
|
-
}
|
|
1566
|
-
hover.appendMarkdown(description);
|
|
1995
|
+
hover.appendMarkdown(operatorDocumentation.description);
|
|
1567
1996
|
return createHoverWithDiagnostics(hover, document, position);
|
|
1568
1997
|
}
|
|
1569
|
-
const
|
|
1570
|
-
|
|
1571
|
-
type: "Window & typeof globalThis",
|
|
1572
|
-
description: "The global window object represents the browser window. Provides access to the DOM, browser APIs, and global variables."
|
|
1573
|
-
},
|
|
1574
|
-
document: {
|
|
1575
|
-
type: "Document",
|
|
1576
|
-
description: "The Document interface represents the web page loaded in the browser. Entry point to the DOM tree."
|
|
1577
|
-
},
|
|
1578
|
-
console: {
|
|
1579
|
-
type: "Console",
|
|
1580
|
-
description: "Provides access to the browser's debugging console with methods like `log()`, `error()`, `warn()`, etc."
|
|
1581
|
-
},
|
|
1582
|
-
navigator: {
|
|
1583
|
-
type: "Navigator",
|
|
1584
|
-
description: "Represents the state and identity of the user agent (browser). Provides information about the browser and device."
|
|
1585
|
-
},
|
|
1586
|
-
location: {
|
|
1587
|
-
type: "Location",
|
|
1588
|
-
description: "Represents the URL of the current document and provides methods to manipulate the browser's location."
|
|
1589
|
-
},
|
|
1590
|
-
localStorage: {
|
|
1591
|
-
type: "Storage",
|
|
1592
|
-
description: "Provides access to the browser's local storage. Data persists even after the browser is closed."
|
|
1593
|
-
},
|
|
1594
|
-
sessionStorage: {
|
|
1595
|
-
type: "Storage",
|
|
1596
|
-
description: "Provides access to the browser's session storage. Data is cleared when the page session ends."
|
|
1597
|
-
},
|
|
1598
|
-
history: {
|
|
1599
|
-
type: "History",
|
|
1600
|
-
description: "Provides an interface for manipulating the browser session history (pages visited in the tab/frame)."
|
|
1601
|
-
},
|
|
1602
|
-
Math: {
|
|
1603
|
-
type: "Math",
|
|
1604
|
-
description: "Built-in object with properties and methods for mathematical constants and functions."
|
|
1605
|
-
},
|
|
1606
|
-
JSON: {
|
|
1607
|
-
type: "JSON",
|
|
1608
|
-
description: "Provides methods for parsing JSON and converting values to JSON: `parse()` and `stringify()`."
|
|
1609
|
-
},
|
|
1610
|
-
globalThis: {
|
|
1611
|
-
type: "typeof globalThis",
|
|
1612
|
-
description: "Provides a standard way to access the global object across different JavaScript environments."
|
|
1613
|
-
}
|
|
1614
|
-
};
|
|
1615
|
-
if (word in globalObjects) {
|
|
1616
|
-
const global = globalObjects[word];
|
|
1998
|
+
const global = GLOBAL_OBJECT_HOVERS[word];
|
|
1999
|
+
if (global) {
|
|
1617
2000
|
const hover = new vscode2.MarkdownString;
|
|
1618
2001
|
hover.isTrusted = true;
|
|
1619
2002
|
hover.supportHtml = true;
|
|
@@ -1968,8 +2351,7 @@ ${cssStyles.join(`
|
|
|
1968
2351
|
const htmlTagOpening = line.includes(`<${word}`);
|
|
1969
2352
|
const htmlTagClosing = line.includes(`</${word}`);
|
|
1970
2353
|
const isHtmlTag = htmlTagOpening || htmlTagClosing || line.match(new RegExp(`<${word}[\\s>]`)) !== null;
|
|
1971
|
-
|
|
1972
|
-
if (htmlTags.includes(word) && isHtmlTag) {
|
|
2354
|
+
if (HTML_TAGS.has(word) && isHtmlTag) {
|
|
1973
2355
|
const hover = new vscode2.MarkdownString;
|
|
1974
2356
|
hover.isTrusted = true;
|
|
1975
2357
|
hover.supportHtml = true;
|
|
@@ -1977,75 +2359,7 @@ ${cssStyles.join(`
|
|
|
1977
2359
|
hover.appendText(`
|
|
1978
2360
|
|
|
1979
2361
|
`);
|
|
1980
|
-
|
|
1981
|
-
switch (word) {
|
|
1982
|
-
case "body":
|
|
1983
|
-
tagDescription = "Main content of the HTML document. Contains all content that is visible to the user.";
|
|
1984
|
-
break;
|
|
1985
|
-
case "div":
|
|
1986
|
-
tagDescription = "Generic container element for flow content with no semantic meaning.";
|
|
1987
|
-
break;
|
|
1988
|
-
case "span":
|
|
1989
|
-
tagDescription = "Generic inline container with no semantic meaning. Used for styling or grouping text.";
|
|
1990
|
-
break;
|
|
1991
|
-
case "p":
|
|
1992
|
-
tagDescription = "Paragraph element representing a block of text.";
|
|
1993
|
-
break;
|
|
1994
|
-
case "h1":
|
|
1995
|
-
case "h2":
|
|
1996
|
-
case "h3":
|
|
1997
|
-
case "h4":
|
|
1998
|
-
case "h5":
|
|
1999
|
-
case "h6":
|
|
2000
|
-
tagDescription = `Level ${word.substring(1)} heading element. H1 is most important, H6 is least important.`;
|
|
2001
|
-
break;
|
|
2002
|
-
case "strong":
|
|
2003
|
-
tagDescription = "Indicates strong importance. Text is typically displayed in bold.";
|
|
2004
|
-
break;
|
|
2005
|
-
case "em":
|
|
2006
|
-
tagDescription = "Marks text that has stress emphasis. Text is typically displayed in italic.";
|
|
2007
|
-
break;
|
|
2008
|
-
case "a":
|
|
2009
|
-
tagDescription = "Anchor element for creating hyperlinks to other pages, files, or locations.";
|
|
2010
|
-
break;
|
|
2011
|
-
case "img":
|
|
2012
|
-
tagDescription = "Embeds an image into the document. Self-closing tag requiring src attribute.";
|
|
2013
|
-
break;
|
|
2014
|
-
case "button":
|
|
2015
|
-
tagDescription = "Clickable button element for forms or interactive elements.";
|
|
2016
|
-
break;
|
|
2017
|
-
case "input":
|
|
2018
|
-
tagDescription = "Form input element for user data entry. Requires type attribute.";
|
|
2019
|
-
break;
|
|
2020
|
-
case "form":
|
|
2021
|
-
tagDescription = "Container for a form with inputs and controls for user submission.";
|
|
2022
|
-
break;
|
|
2023
|
-
case "ul":
|
|
2024
|
-
tagDescription = "Unordered list container. Contains li elements.";
|
|
2025
|
-
break;
|
|
2026
|
-
case "ol":
|
|
2027
|
-
tagDescription = "Ordered (numbered) list container. Contains li elements.";
|
|
2028
|
-
break;
|
|
2029
|
-
case "li":
|
|
2030
|
-
tagDescription = "List item element. Used within ul or ol containers.";
|
|
2031
|
-
break;
|
|
2032
|
-
case "table":
|
|
2033
|
-
tagDescription = "Container for tabular data with rows and columns.";
|
|
2034
|
-
break;
|
|
2035
|
-
case "pre":
|
|
2036
|
-
tagDescription = "Preformatted text element. Preserves whitespace and line breaks.";
|
|
2037
|
-
break;
|
|
2038
|
-
case "code":
|
|
2039
|
-
tagDescription = "Represents computer code within a document.";
|
|
2040
|
-
break;
|
|
2041
|
-
case "label":
|
|
2042
|
-
tagDescription = "Label for a form element. Improves accessibility and usability.";
|
|
2043
|
-
break;
|
|
2044
|
-
default:
|
|
2045
|
-
tagDescription = `HTML ${word} element`;
|
|
2046
|
-
break;
|
|
2047
|
-
}
|
|
2048
|
-
hover.appendMarkdown(tagDescription);
|
|
2362
|
+
hover.appendMarkdown(htmlTagDescription(word));
|
|
2049
2363
|
hover.appendMarkdown(`
|
|
2050
2364
|
|
|
2051
2365
|
[MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/${word})`);
|
|
@@ -2075,120 +2389,15 @@ ${cssStyles.join(`
|
|
|
2075
2389
|
}
|
|
2076
2390
|
}
|
|
2077
2391
|
}
|
|
2078
|
-
const
|
|
2079
|
-
const
|
|
2080
|
-
const directiveMatch = line.match(/@(\w+)/);
|
|
2081
|
-
const possibleDirective = directiveMatch ? directiveMatch[1] : null;
|
|
2082
|
-
const isAtOrDirective = word.startsWith("@") || word === possibleDirective || wordAfterAt;
|
|
2392
|
+
const directiveContext = getStxDirectiveAtOffset(line, position.character);
|
|
2393
|
+
const isAtOrDirective = directiveContext !== undefined;
|
|
2083
2394
|
if (isAtOrDirective) {
|
|
2084
|
-
|
|
2085
|
-
if (word.startsWith("@")) {
|
|
2086
|
-
directiveName = word.substring(1);
|
|
2087
|
-
} else if (wordAfterAt && possibleDirective === word) {
|
|
2088
|
-
directiveName = word;
|
|
2089
|
-
}
|
|
2395
|
+
const directiveName = directiveContext.name;
|
|
2090
2396
|
if (directiveName.length === 0 || directiveName === "@") {
|
|
2091
2397
|
return null;
|
|
2092
2398
|
}
|
|
2093
|
-
const
|
|
2094
|
-
|
|
2095
|
-
"else",
|
|
2096
|
-
"elseif",
|
|
2097
|
-
"elif",
|
|
2098
|
-
"endif",
|
|
2099
|
-
"unless",
|
|
2100
|
-
"endunless",
|
|
2101
|
-
"for",
|
|
2102
|
-
"endfor",
|
|
2103
|
-
"foreach",
|
|
2104
|
-
"endforeach",
|
|
2105
|
-
"forelse",
|
|
2106
|
-
"endforelse",
|
|
2107
|
-
"while",
|
|
2108
|
-
"endwhile",
|
|
2109
|
-
"switch",
|
|
2110
|
-
"case",
|
|
2111
|
-
"default",
|
|
2112
|
-
"endswitch",
|
|
2113
|
-
"break",
|
|
2114
|
-
"continue",
|
|
2115
|
-
"component",
|
|
2116
|
-
"endcomponent",
|
|
2117
|
-
"slot",
|
|
2118
|
-
"endslot",
|
|
2119
|
-
"webcomponent",
|
|
2120
|
-
"endwebcomponent",
|
|
2121
|
-
"ts",
|
|
2122
|
-
"endts",
|
|
2123
|
-
"js",
|
|
2124
|
-
"endjs",
|
|
2125
|
-
"script",
|
|
2126
|
-
"endscript",
|
|
2127
|
-
"css",
|
|
2128
|
-
"endcss",
|
|
2129
|
-
"json",
|
|
2130
|
-
"markdown",
|
|
2131
|
-
"endmarkdown",
|
|
2132
|
-
"raw",
|
|
2133
|
-
"endraw",
|
|
2134
|
-
"verbatim",
|
|
2135
|
-
"endverbatim",
|
|
2136
|
-
"t",
|
|
2137
|
-
"translate",
|
|
2138
|
-
"extends",
|
|
2139
|
-
"section",
|
|
2140
|
-
"endsection",
|
|
2141
|
-
"yield",
|
|
2142
|
-
"parent",
|
|
2143
|
-
"stack",
|
|
2144
|
-
"push",
|
|
2145
|
-
"endpush",
|
|
2146
|
-
"pushif",
|
|
2147
|
-
"endpushif",
|
|
2148
|
-
"pushonce",
|
|
2149
|
-
"endpushonce",
|
|
2150
|
-
"prepend",
|
|
2151
|
-
"endprepend",
|
|
2152
|
-
"prependonce",
|
|
2153
|
-
"endprependonce",
|
|
2154
|
-
"include",
|
|
2155
|
-
"includeif",
|
|
2156
|
-
"includewhen",
|
|
2157
|
-
"includeunless",
|
|
2158
|
-
"includefirst",
|
|
2159
|
-
"auth",
|
|
2160
|
-
"endauth",
|
|
2161
|
-
"guest",
|
|
2162
|
-
"endguest",
|
|
2163
|
-
"can",
|
|
2164
|
-
"endcan",
|
|
2165
|
-
"cannot",
|
|
2166
|
-
"endcannot",
|
|
2167
|
-
"elsecan",
|
|
2168
|
-
"env",
|
|
2169
|
-
"endenv",
|
|
2170
|
-
"isset",
|
|
2171
|
-
"endisset",
|
|
2172
|
-
"empty",
|
|
2173
|
-
"endempty",
|
|
2174
|
-
"error",
|
|
2175
|
-
"enderror",
|
|
2176
|
-
"hassection",
|
|
2177
|
-
"once",
|
|
2178
|
-
"endonce",
|
|
2179
|
-
"use",
|
|
2180
|
-
"csrf",
|
|
2181
|
-
"method",
|
|
2182
|
-
"locale",
|
|
2183
|
-
"transition",
|
|
2184
|
-
"endtransition",
|
|
2185
|
-
"motion",
|
|
2186
|
-
"endmotion",
|
|
2187
|
-
"animationgroup",
|
|
2188
|
-
"scrollanimate",
|
|
2189
|
-
"endscrollanimate"
|
|
2190
|
-
];
|
|
2191
|
-
if (!validDirectives.includes(directiveName.toLowerCase())) {
|
|
2399
|
+
const directiveDefinition = STX_DIRECTIVE_BY_NAME.get(directiveName.toLowerCase());
|
|
2400
|
+
if (!directiveDefinition) {
|
|
2192
2401
|
return null;
|
|
2193
2402
|
}
|
|
2194
2403
|
const hover = new vscode2.MarkdownString;
|
|
@@ -3765,8 +3974,13 @@ errors.notFound: "Page not found"`, "yaml");
|
|
|
3765
3974
|
}
|
|
3766
3975
|
return createHoverWithDiagnostics(hover, document, position);
|
|
3767
3976
|
default:
|
|
3768
|
-
description =
|
|
3977
|
+
description = directiveDefinition.description;
|
|
3769
3978
|
hover.appendMarkdown(description);
|
|
3979
|
+
hover.appendMarkdown(`
|
|
3980
|
+
|
|
3981
|
+
**Syntax**
|
|
3982
|
+
`);
|
|
3983
|
+
hover.appendCodeblock(stxSnippetPreview(directiveDefinition.snippet ?? `@${directiveDefinition.name}`), "stx");
|
|
3770
3984
|
return createHoverWithDiagnostics(hover, document, position);
|
|
3771
3985
|
}
|
|
3772
3986
|
}
|
|
@@ -3982,7 +4196,6 @@ errors.notFound: "Page not found"`, "yaml");
|
|
|
3982
4196
|
const arrowFunctionMatch = tsContent.match(new RegExp(`const\\s+${word}\\s*=\\s*\\([^)]*\\)\\s*:[^=]+=>`, "s"));
|
|
3983
4197
|
const isArrowFunction = arrowFunctionMatch !== null;
|
|
3984
4198
|
const htmlTagMatch = line.match(new RegExp(`<(/)?${word}(\\s|/?>|$)`));
|
|
3985
|
-
const commonHtmlTags = ["div", "span", "p", "h1", "h2", "h3", "h4", "h5", "h6", "strong", "em", "a", "img", "button", "input", "form", "label", "ul", "ol", "li", "table", "tr", "td", "th", "pre", "code", "body", "html", "head", "header", "footer", "main", "section", "article", "aside"];
|
|
3986
4199
|
const isActuallyHtmlTag = htmlTagMatch !== null;
|
|
3987
4200
|
const isInCodeContext = isInScriptTag(document, position) || line.includes("@ts") || line.includes("{{");
|
|
3988
4201
|
const mightBeHtmlTag = isActuallyHtmlTag && !isInCodeContext;
|
|
@@ -4352,6 +4565,7 @@ function createCompletionProvider() {
|
|
|
4352
4565
|
provideCompletionItems(document, position, token, context) {
|
|
4353
4566
|
const config = vscode3.workspace.getConfiguration("stx.completion");
|
|
4354
4567
|
const completionEnabled = config.get("enable", true);
|
|
4568
|
+
const showSnippets = config.get("showSnippets", true);
|
|
4355
4569
|
if (!completionEnabled) {
|
|
4356
4570
|
return;
|
|
4357
4571
|
}
|
|
@@ -4363,21 +4577,26 @@ function createCompletionProvider() {
|
|
|
4363
4577
|
console.log(`stx Completion - Processing document: ${document.fileName} (language: ${document.languageId})`);
|
|
4364
4578
|
const line = document.lineAt(position.line).text;
|
|
4365
4579
|
const linePrefix = line.substring(0, position.character);
|
|
4580
|
+
const sourceBeforeCursor = document.getText().slice(0, document.offsetAt(position));
|
|
4581
|
+
const attributeContext = getStxAttributeCompletionContext(sourceBeforeCursor);
|
|
4366
4582
|
console.log(`stx Completion - Processing line prefix: "${linePrefix}"`);
|
|
4367
4583
|
console.log(`stx Completion - Trigger character: "${context?.triggerCharacter || "none"}"`);
|
|
4584
|
+
if (attributeContext) {
|
|
4585
|
+
return getAttributeDirectiveCompletions(attributeContext.prefix, position, showSnippets);
|
|
4586
|
+
}
|
|
4368
4587
|
if (context?.triggerCharacter === "@") {
|
|
4369
4588
|
console.log(`stx Completion - Triggered by @ character, showing all directives`);
|
|
4370
|
-
return getAllDirectiveCompletions();
|
|
4589
|
+
return getAllDirectiveCompletions(showSnippets);
|
|
4371
4590
|
}
|
|
4372
|
-
const directiveMatch = linePrefix.match(/@([a-z]*)$/i);
|
|
4591
|
+
const directiveMatch = linePrefix.match(/@([a-z:]*)$/i);
|
|
4373
4592
|
if (directiveMatch) {
|
|
4374
4593
|
const prefix = directiveMatch[1].toLowerCase();
|
|
4375
4594
|
console.log(`stx Completion - Found directive prefix: "${prefix}"`);
|
|
4376
|
-
return getFilteredDirectiveCompletions(prefix);
|
|
4595
|
+
return getFilteredDirectiveCompletions(prefix, showSnippets);
|
|
4377
4596
|
}
|
|
4378
4597
|
if (linePrefix.endsWith("@")) {
|
|
4379
4598
|
console.log(`stx Completion - Line ends with @, showing all directives`);
|
|
4380
|
-
return getAllDirectiveCompletions();
|
|
4599
|
+
return getAllDirectiveCompletions(showSnippets);
|
|
4381
4600
|
}
|
|
4382
4601
|
if (linePrefix.includes("@transition(")) {
|
|
4383
4602
|
console.log(`stx Completion - Detected @transition parameters context`);
|
|
@@ -4411,113 +4630,31 @@ function createCompletionProvider() {
|
|
|
4411
4630
|
}
|
|
4412
4631
|
};
|
|
4413
4632
|
}
|
|
4414
|
-
function
|
|
4415
|
-
|
|
4633
|
+
function getAttributeDirectiveCompletions(prefix, position, showSnippets) {
|
|
4634
|
+
const normalizedPrefix = prefix.toLowerCase();
|
|
4635
|
+
const directives = STX_ATTRIBUTE_DIRECTIVES.filter((directive) => directive.name.toLowerCase().startsWith(normalizedPrefix));
|
|
4636
|
+
const start = position.translate(0, -prefix.length);
|
|
4637
|
+
const range = new vscode3.Range(start, position);
|
|
4638
|
+
return directives.map((directive) => createAttributeDirectiveItem(directive, range, showSnippets));
|
|
4416
4639
|
}
|
|
4417
|
-
function
|
|
4418
|
-
const
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4640
|
+
function createAttributeDirectiveItem(directive, range, showSnippets) {
|
|
4641
|
+
const item = new vscode3.CompletionItem(directive.name, vscode3.CompletionItemKind.Property);
|
|
4642
|
+
item.detail = `stx ${directive.name} attribute`;
|
|
4643
|
+
item.documentation = new vscode3.MarkdownString(directive.description);
|
|
4644
|
+
item.insertText = showSnippets ? new vscode3.SnippetString(directive.snippet) : directive.name;
|
|
4645
|
+
item.range = range;
|
|
4646
|
+
item.sortText = directive.name.startsWith(":") ? `0${directive.name}` : `1${directive.name}`;
|
|
4647
|
+
return item;
|
|
4422
4648
|
}
|
|
4423
|
-
function
|
|
4424
|
-
return
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
{ name: "t", description: "Short alias for translate directive" },
|
|
4431
|
-
{ name: "if", description: "Conditional rendering" },
|
|
4432
|
-
{ name: "else", description: "Alternative rendering for conditionals" },
|
|
4433
|
-
{ name: "elseif", description: "Alternative condition for if statement" },
|
|
4434
|
-
{ name: "unless", description: "Inverse conditional rendering" },
|
|
4435
|
-
{ name: "foreach", description: "Iterates over an array or collection" },
|
|
4436
|
-
{ name: "for", description: "Standard for loop" },
|
|
4437
|
-
{ name: "while", description: "While loop" },
|
|
4438
|
-
{ name: "forelse", description: "Loop with fallback when collection is empty" },
|
|
4439
|
-
{ name: "switch", description: "Switch statement for multiple conditions" },
|
|
4440
|
-
{ name: "case", description: "Case option in switch statement" },
|
|
4441
|
-
{ name: "default", description: "Default case in switch statement" },
|
|
4442
|
-
{ name: "break", description: "Break from loop or switch" },
|
|
4443
|
-
{ name: "continue", description: "Continue to next iteration" },
|
|
4444
|
-
{ name: "component", description: "Renders a component" },
|
|
4445
|
-
{ name: "slot", description: "Define a named slot in a component" },
|
|
4446
|
-
{ name: "webcomponent", description: "Include a web component" },
|
|
4447
|
-
{ name: "ts", description: "TypeScript code block" },
|
|
4448
|
-
{ name: "js", description: "JavaScript code block" },
|
|
4449
|
-
{ name: "script", description: "Script code block (alternative to @ts)" },
|
|
4450
|
-
{ name: "css", description: "CSS code block" },
|
|
4451
|
-
{ name: "json", description: "Output variable as JSON" },
|
|
4452
|
-
{ name: "markdown", description: "Markdown content block" },
|
|
4453
|
-
{ name: "raw", description: "Display content without processing expressions" },
|
|
4454
|
-
{ name: "verbatim", description: "Display content without processing directives" },
|
|
4455
|
-
{ name: "extends", description: "Extend a base layout" },
|
|
4456
|
-
{ name: "section", description: "Define a content section" },
|
|
4457
|
-
{ name: "yield", description: "Output the contents of a section" },
|
|
4458
|
-
{ name: "parent", description: "Include parent section content" },
|
|
4459
|
-
{ name: "stack", description: "Define a stack for pushing content" },
|
|
4460
|
-
{ name: "push", description: "Push content to a stack" },
|
|
4461
|
-
{ name: "pushIf", description: "Conditionally push content to a stack" },
|
|
4462
|
-
{ name: "pushOnce", description: "Push content to a stack only once" },
|
|
4463
|
-
{ name: "prepend", description: "Prepend content to a stack" },
|
|
4464
|
-
{ name: "prependOnce", description: "Prepend content to a stack only once" },
|
|
4465
|
-
{ name: "include", description: "Include another template file" },
|
|
4466
|
-
{ name: "includeIf", description: "Conditionally include a template" },
|
|
4467
|
-
{ name: "includeWhen", description: "Include template when condition is true" },
|
|
4468
|
-
{ name: "includeUnless", description: "Include template unless condition is true" },
|
|
4469
|
-
{ name: "includeFirst", description: "Include the first existing template from a list" },
|
|
4470
|
-
{ name: "auth", description: "Content visible only to authenticated users" },
|
|
4471
|
-
{ name: "guest", description: "Content visible only to guests" },
|
|
4472
|
-
{ name: "can", description: "Check if user has permission" },
|
|
4473
|
-
{ name: "cannot", description: "Check if user lacks permission" },
|
|
4474
|
-
{ name: "env", description: "Check environment condition" },
|
|
4475
|
-
{ name: "isset", description: "Check if a variable is set" },
|
|
4476
|
-
{ name: "empty", description: "Check if a variable is empty" },
|
|
4477
|
-
{ name: "error", description: "Display validation error for a field" },
|
|
4478
|
-
{ name: "hasSection", description: "Check if a section exists" },
|
|
4479
|
-
{ name: "once", description: "Include content only once per rendering cycle" },
|
|
4480
|
-
{ name: "use", description: "Import a class or namespace" },
|
|
4481
|
-
{ name: "csrf", description: "Include CSRF protection token" },
|
|
4482
|
-
{ name: "method", description: "Specify form submission method" },
|
|
4483
|
-
{ name: "locale", description: "Set locale for content" },
|
|
4484
|
-
{ name: "endtransition", description: "Ends a transition block" },
|
|
4485
|
-
{ name: "endmotion", description: "Ends a motion block" },
|
|
4486
|
-
{ name: "endif", description: "Ends an if block" },
|
|
4487
|
-
{ name: "endunless", description: "Ends an unless block" },
|
|
4488
|
-
{ name: "endfor", description: "Ends a for loop block" },
|
|
4489
|
-
{ name: "endforeach", description: "Ends a foreach loop block" },
|
|
4490
|
-
{ name: "endforelse", description: "Ends a forelse loop block" },
|
|
4491
|
-
{ name: "endwhile", description: "Ends a while loop block" },
|
|
4492
|
-
{ name: "endswitch", description: "Ends a switch block" },
|
|
4493
|
-
{ name: "endts", description: "Ends a TypeScript code block" },
|
|
4494
|
-
{ name: "endjs", description: "Ends a JavaScript code block" },
|
|
4495
|
-
{ name: "endscript", description: "Ends a script code block" },
|
|
4496
|
-
{ name: "endcss", description: "Ends a CSS code block" },
|
|
4497
|
-
{ name: "endmarkdown", description: "Ends a markdown block" },
|
|
4498
|
-
{ name: "endraw", description: "Ends a raw content block" },
|
|
4499
|
-
{ name: "endverbatim", description: "Ends a verbatim block" },
|
|
4500
|
-
{ name: "endcomponent", description: "Ends a component block" },
|
|
4501
|
-
{ name: "endslot", description: "Ends a slot block" },
|
|
4502
|
-
{ name: "endsection", description: "Ends a section block" },
|
|
4503
|
-
{ name: "endpush", description: "Ends a push block" },
|
|
4504
|
-
{ name: "endpushIf", description: "Ends a pushIf block" },
|
|
4505
|
-
{ name: "endpushOnce", description: "Ends a pushOnce block" },
|
|
4506
|
-
{ name: "endprepend", description: "Ends a prepend block" },
|
|
4507
|
-
{ name: "endprependOnce", description: "Ends a prependOnce block" },
|
|
4508
|
-
{ name: "endauth", description: "Ends an auth block" },
|
|
4509
|
-
{ name: "endguest", description: "Ends a guest block" },
|
|
4510
|
-
{ name: "endcan", description: "Ends a can block" },
|
|
4511
|
-
{ name: "endcannot", description: "Ends a cannot block" },
|
|
4512
|
-
{ name: "endempty", description: "Ends an empty block" },
|
|
4513
|
-
{ name: "endenv", description: "Ends an env block" },
|
|
4514
|
-
{ name: "endisset", description: "Ends an isset block" },
|
|
4515
|
-
{ name: "enderror", description: "Ends an error block" },
|
|
4516
|
-
{ name: "endonce", description: "Ends a once block" },
|
|
4517
|
-
{ name: "endwebcomponent", description: "Ends a webcomponent block" }
|
|
4518
|
-
];
|
|
4649
|
+
function getAllDirectiveCompletions(showSnippets) {
|
|
4650
|
+
return createDirectiveItems(STX_DIRECTIVES, showSnippets);
|
|
4651
|
+
}
|
|
4652
|
+
function getFilteredDirectiveCompletions(prefix, showSnippets) {
|
|
4653
|
+
const filteredDirectives = STX_DIRECTIVES.filter((d) => d.name.toLowerCase().includes(prefix.toLowerCase()));
|
|
4654
|
+
console.log(`stx Completion - Filtered directives: ${filteredDirectives.map((d) => d.name).join(", ")}`);
|
|
4655
|
+
return createDirectiveItems(filteredDirectives, showSnippets);
|
|
4519
4656
|
}
|
|
4520
|
-
function createDirectiveItems(directives) {
|
|
4657
|
+
function createDirectiveItems(directives, showSnippets) {
|
|
4521
4658
|
return directives.map((directive) => {
|
|
4522
4659
|
const item = new vscode3.CompletionItem(`@${directive.name}`, vscode3.CompletionItemKind.Snippet);
|
|
4523
4660
|
item.detail = `stx ${directive.name} directive`;
|
|
@@ -4712,9 +4849,11 @@ function createDirectiveItems(directives) {
|
|
|
4712
4849
|
item.insertText = new vscode3.SnippetString("@animationGroup(${1:groupName}, ${2:#selector1})");
|
|
4713
4850
|
break;
|
|
4714
4851
|
default:
|
|
4715
|
-
item.insertText = new vscode3.SnippetString(`@${directive.name}`);
|
|
4852
|
+
item.insertText = new vscode3.SnippetString(directive.snippet ?? `@${directive.name}`);
|
|
4716
4853
|
break;
|
|
4717
4854
|
}
|
|
4855
|
+
if (!showSnippets)
|
|
4856
|
+
item.insertText = `@${directive.name}`;
|
|
4718
4857
|
if (["transition", "motion", "translate", "component", "if", "foreach"].includes(directive.name)) {
|
|
4719
4858
|
item.sortText = `0${directive.name}`;
|
|
4720
4859
|
} else {
|
|
@@ -4861,20 +5000,122 @@ function createPropsCompletions(document, partialProp) {
|
|
|
4861
5000
|
// ../vscode/src/providers/definitionProvider.ts
|
|
4862
5001
|
import * as vscode5 from "vscode";
|
|
4863
5002
|
|
|
5003
|
+
// ../vscode/src/utils/template-paths.ts
|
|
5004
|
+
var TEMPLATE_SEARCH_DIRECTORIES = [
|
|
5005
|
+
"",
|
|
5006
|
+
"views",
|
|
5007
|
+
"templates",
|
|
5008
|
+
"resources/views",
|
|
5009
|
+
"resources/templates",
|
|
5010
|
+
"src/views",
|
|
5011
|
+
"src/templates",
|
|
5012
|
+
"app/views",
|
|
5013
|
+
"partials",
|
|
5014
|
+
"components",
|
|
5015
|
+
"layouts",
|
|
5016
|
+
"examples/partials",
|
|
5017
|
+
"examples/components"
|
|
5018
|
+
];
|
|
5019
|
+
var COMPONENT_SEARCH_DIRECTORIES = [
|
|
5020
|
+
"components",
|
|
5021
|
+
"resources/views/components",
|
|
5022
|
+
"src/components",
|
|
5023
|
+
"app/components",
|
|
5024
|
+
"ui",
|
|
5025
|
+
"src/ui"
|
|
5026
|
+
];
|
|
5027
|
+
var TEMPLATE_DIRECTIVE_PATTERN = /@(includeFirst|includeUnless|includeWhen|includeIf|include|webcomponent|component)\s*\(/g;
|
|
5028
|
+
function argumentStart(source, openParen, targetArgument) {
|
|
5029
|
+
if (targetArgument === 0)
|
|
5030
|
+
return openParen + 1;
|
|
5031
|
+
let argument = 0;
|
|
5032
|
+
let depth = 0;
|
|
5033
|
+
let quote = "";
|
|
5034
|
+
for (let index = openParen + 1;index < source.length; index++) {
|
|
5035
|
+
const character = source[index];
|
|
5036
|
+
if (quote) {
|
|
5037
|
+
if (character === "\\")
|
|
5038
|
+
index++;
|
|
5039
|
+
else if (character === quote)
|
|
5040
|
+
quote = "";
|
|
5041
|
+
continue;
|
|
5042
|
+
}
|
|
5043
|
+
if (character === "'" || character === '"' || character === "`") {
|
|
5044
|
+
quote = character;
|
|
5045
|
+
} else if (character === "(" || character === "[" || character === "{") {
|
|
5046
|
+
depth++;
|
|
5047
|
+
} else if (character === ")" || character === "]" || character === "}") {
|
|
5048
|
+
if (character === ")" && depth === 0)
|
|
5049
|
+
return;
|
|
5050
|
+
depth--;
|
|
5051
|
+
} else if (character === "," && depth === 0) {
|
|
5052
|
+
argument++;
|
|
5053
|
+
if (argument === targetArgument)
|
|
5054
|
+
return index + 1;
|
|
5055
|
+
}
|
|
5056
|
+
}
|
|
5057
|
+
return;
|
|
5058
|
+
}
|
|
5059
|
+
function quotedReferences(source, start, end = source.length) {
|
|
5060
|
+
const references = [];
|
|
5061
|
+
for (let index = start;index < end; index++) {
|
|
5062
|
+
const quote = source[index];
|
|
5063
|
+
if (quote !== "'" && quote !== '"' && quote !== "`")
|
|
5064
|
+
continue;
|
|
5065
|
+
const pathStart = index + 1;
|
|
5066
|
+
let pathEnd = pathStart;
|
|
5067
|
+
while (pathEnd < end && source[pathEnd] !== quote) {
|
|
5068
|
+
if (source[pathEnd] === "\\")
|
|
5069
|
+
pathEnd++;
|
|
5070
|
+
pathEnd++;
|
|
5071
|
+
}
|
|
5072
|
+
if (pathEnd < end) {
|
|
5073
|
+
references.push({ path: source.slice(pathStart, pathEnd), start: pathStart, end: pathEnd });
|
|
5074
|
+
index = pathEnd;
|
|
5075
|
+
}
|
|
5076
|
+
}
|
|
5077
|
+
return references;
|
|
5078
|
+
}
|
|
5079
|
+
function getTemplatePathCompletionContext(linePrefix) {
|
|
5080
|
+
TEMPLATE_DIRECTIVE_PATTERN.lastIndex = 0;
|
|
5081
|
+
const directives = [...linePrefix.matchAll(TEMPLATE_DIRECTIVE_PATTERN)];
|
|
5082
|
+
const directive = directives[directives.length - 1];
|
|
5083
|
+
if (!directive)
|
|
5084
|
+
return;
|
|
5085
|
+
const name = directive[1];
|
|
5086
|
+
const openParen = directive.index + directive[0].lastIndexOf("(");
|
|
5087
|
+
const targetArgument = name === "includeWhen" || name === "includeUnless" ? 1 : 0;
|
|
5088
|
+
const start = argumentStart(linePrefix, openParen, targetArgument);
|
|
5089
|
+
if (start === undefined)
|
|
5090
|
+
return;
|
|
5091
|
+
const argument = linePrefix.slice(start);
|
|
5092
|
+
const pathMatch = name === "includeFirst" ? argument.match(/\[[\s\S]*['"`]([^'"`]*)$/) : argument.match(/^\s*['"`]([^'"`]*)$/);
|
|
5093
|
+
return pathMatch ? { kind: name === "component" || name === "webcomponent" ? "component" : "include", path: pathMatch[1] } : undefined;
|
|
5094
|
+
}
|
|
5095
|
+
function findTemplatePathReferences(line) {
|
|
5096
|
+
const references = [];
|
|
5097
|
+
TEMPLATE_DIRECTIVE_PATTERN.lastIndex = 0;
|
|
5098
|
+
for (const directive of line.matchAll(TEMPLATE_DIRECTIVE_PATTERN)) {
|
|
5099
|
+
const name = directive[1];
|
|
5100
|
+
const openParen = directive.index + directive[0].lastIndexOf("(");
|
|
5101
|
+
const targetArgument = name === "includeWhen" || name === "includeUnless" ? 1 : 0;
|
|
5102
|
+
const start = argumentStart(line, openParen, targetArgument);
|
|
5103
|
+
if (start === undefined)
|
|
5104
|
+
continue;
|
|
5105
|
+
const kind = name === "component" || name === "webcomponent" ? "component" : "include";
|
|
5106
|
+
const candidates = name === "includeFirst" ? quotedReferences(line, line.indexOf("[", start) + 1, line.indexOf("]", start)) : quotedReferences(line, start).slice(0, 1);
|
|
5107
|
+
for (const candidate of candidates)
|
|
5108
|
+
references.push({ kind, ...candidate });
|
|
5109
|
+
}
|
|
5110
|
+
return references.sort((a, b) => a.start - b.start);
|
|
5111
|
+
}
|
|
5112
|
+
|
|
4864
5113
|
// ../vscode/src/utils/templateUtils.ts
|
|
4865
5114
|
import * as fs2 from "node:fs";
|
|
4866
5115
|
import * as path3 from "node:path";
|
|
4867
5116
|
import * as vscode4 from "vscode";
|
|
4868
5117
|
function extractTemplatePath(line) {
|
|
4869
|
-
|
|
4870
|
-
if (regularMatch && regularMatch[1]) {
|
|
4871
|
-
return regularMatch[1];
|
|
4872
|
-
}
|
|
4873
|
-
const conditionalMatch = line.match(/@(?:includeIf|includeWhen|includeUnless|includeFirst)\s*\([^,]*,\s*['"]([^'"]+)['"]/);
|
|
4874
|
-
if (conditionalMatch && conditionalMatch[1]) {
|
|
4875
|
-
return conditionalMatch[1];
|
|
4876
|
-
}
|
|
4877
|
-
return null;
|
|
5118
|
+
return findTemplatePathReferences(line)[0]?.path ?? null;
|
|
4878
5119
|
}
|
|
4879
5120
|
function normalizeTemplatePath(templatePath) {
|
|
4880
5121
|
let normalizedPath = templatePath.replace(/\./g, "/");
|
|
@@ -4894,18 +5135,11 @@ function resolveTemplatePath(documentUri, templatePath) {
|
|
|
4894
5135
|
if (fs2.existsSync(relativePath)) {
|
|
4895
5136
|
return vscode4.Uri.file(relativePath);
|
|
4896
5137
|
}
|
|
4897
|
-
const
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
"components",
|
|
4903
|
-
"resources/views",
|
|
4904
|
-
"resources/templates",
|
|
4905
|
-
"examples/partials",
|
|
4906
|
-
"examples/components"
|
|
4907
|
-
];
|
|
4908
|
-
for (const dir of searchDirs) {
|
|
5138
|
+
const searchDirectories = [...new Set([
|
|
5139
|
+
...TEMPLATE_SEARCH_DIRECTORIES,
|
|
5140
|
+
...COMPONENT_SEARCH_DIRECTORIES
|
|
5141
|
+
])];
|
|
5142
|
+
for (const dir of searchDirectories) {
|
|
4909
5143
|
const fullPath = path3.join(workspaceFolder.uri.fsPath, dir, normalizedPath);
|
|
4910
5144
|
if (fs2.existsSync(fullPath)) {
|
|
4911
5145
|
return vscode4.Uri.file(fullPath);
|
|
@@ -4915,45 +5149,27 @@ function resolveTemplatePath(documentUri, templatePath) {
|
|
|
4915
5149
|
}
|
|
4916
5150
|
function getTemplatePathRange(document, line) {
|
|
4917
5151
|
const lineText = document.lineAt(line).text;
|
|
4918
|
-
const
|
|
4919
|
-
|
|
4920
|
-
const startPos = lineText.indexOf(regularMatch[2], regularMatch.index);
|
|
4921
|
-
const endPos = startPos + regularMatch[2].length;
|
|
4922
|
-
return new vscode4.Range(new vscode4.Position(line, startPos), new vscode4.Position(line, endPos));
|
|
4923
|
-
}
|
|
4924
|
-
const conditionalMatch = lineText.match(/@(?:includeIf|includeWhen|includeUnless|includeFirst)\s*\([^,]*,\s*(['"])([^'"]+)\1/);
|
|
4925
|
-
if (conditionalMatch) {
|
|
4926
|
-
const startPos = lineText.indexOf(conditionalMatch[2], conditionalMatch.index);
|
|
4927
|
-
const endPos = startPos + conditionalMatch[2].length;
|
|
4928
|
-
return new vscode4.Range(new vscode4.Position(line, startPos), new vscode4.Position(line, endPos));
|
|
4929
|
-
}
|
|
4930
|
-
return null;
|
|
5152
|
+
const reference = findTemplatePathReferences(lineText)[0];
|
|
5153
|
+
return reference ? new vscode4.Range(line, reference.start, line, reference.end) : null;
|
|
4931
5154
|
}
|
|
4932
5155
|
|
|
4933
5156
|
// ../vscode/src/providers/definitionProvider.ts
|
|
4934
5157
|
function createDefinitionProvider(virtualTsDocumentProvider) {
|
|
4935
5158
|
return {
|
|
4936
5159
|
async provideDefinition(document, position, token) {
|
|
5160
|
+
const line = document.lineAt(position.line).text;
|
|
5161
|
+
const templateReference = findTemplatePathReferences(line).find((reference) => position.character >= reference.start && position.character <= reference.end);
|
|
5162
|
+
if (templateReference) {
|
|
5163
|
+
const resolvedUri = resolveTemplatePath(document.uri, templateReference.path);
|
|
5164
|
+
if (resolvedUri) {
|
|
5165
|
+
return new vscode5.Location(resolvedUri, new vscode5.Position(0, 0));
|
|
5166
|
+
}
|
|
5167
|
+
}
|
|
4937
5168
|
const wordRange = document.getWordRangeAtPosition(position);
|
|
4938
5169
|
if (!wordRange) {
|
|
4939
5170
|
return null;
|
|
4940
5171
|
}
|
|
4941
5172
|
const word = document.getText(wordRange);
|
|
4942
|
-
const line = document.lineAt(position.line).text;
|
|
4943
|
-
const isRegularDirective = /@(include|component)\s*\(/.test(line);
|
|
4944
|
-
const isConditionalDirective = /@(includeIf|includeWhen|includeUnless|includeFirst)\s*\([^,]*,/.test(line);
|
|
4945
|
-
if (isRegularDirective || isConditionalDirective) {
|
|
4946
|
-
const templatePath = extractTemplatePath(line);
|
|
4947
|
-
if (templatePath) {
|
|
4948
|
-
const templatePathRange = getTemplatePathRange(document, position.line);
|
|
4949
|
-
if (templatePathRange && templatePathRange.contains(position)) {
|
|
4950
|
-
const resolvedUri = resolveTemplatePath(document.uri, templatePath);
|
|
4951
|
-
if (resolvedUri) {
|
|
4952
|
-
return new vscode5.Location(resolvedUri, new vscode5.Position(0, 0));
|
|
4953
|
-
}
|
|
4954
|
-
}
|
|
4955
|
-
}
|
|
4956
|
-
}
|
|
4957
5173
|
const classAttributeRegex = /(class|className)\s*=\s*["']([^"']*)["']/g;
|
|
4958
5174
|
let classAttributeMatch;
|
|
4959
5175
|
let isInClassAttribute = false;
|
|
@@ -5038,43 +5254,6 @@ function createDiagnosticsProvider(context) {
|
|
|
5038
5254
|
}));
|
|
5039
5255
|
return diagnosticCollection;
|
|
5040
5256
|
}
|
|
5041
|
-
var directivePairs = {
|
|
5042
|
-
if: "endif",
|
|
5043
|
-
unless: "endunless",
|
|
5044
|
-
for: "endfor",
|
|
5045
|
-
foreach: "endforeach",
|
|
5046
|
-
forelse: "endforelse",
|
|
5047
|
-
while: "endwhile",
|
|
5048
|
-
switch: "endswitch",
|
|
5049
|
-
ts: "endts",
|
|
5050
|
-
js: "endjs",
|
|
5051
|
-
script: "endscript",
|
|
5052
|
-
css: "endcss",
|
|
5053
|
-
markdown: "endmarkdown",
|
|
5054
|
-
raw: "endraw",
|
|
5055
|
-
verbatim: "endverbatim",
|
|
5056
|
-
component: "endcomponent",
|
|
5057
|
-
slot: "endslot",
|
|
5058
|
-
webcomponent: "endwebcomponent",
|
|
5059
|
-
section: "endsection",
|
|
5060
|
-
push: "endpush",
|
|
5061
|
-
pushIf: "endpushIf",
|
|
5062
|
-
pushOnce: "endpushOnce",
|
|
5063
|
-
prepend: "endprepend",
|
|
5064
|
-
prependOnce: "endprependOnce",
|
|
5065
|
-
auth: "endauth",
|
|
5066
|
-
guest: "endguest",
|
|
5067
|
-
can: "endcan",
|
|
5068
|
-
cannot: "endcannot",
|
|
5069
|
-
env: "endenv",
|
|
5070
|
-
isset: "endisset",
|
|
5071
|
-
empty: "endempty",
|
|
5072
|
-
error: "enderror",
|
|
5073
|
-
once: "endonce",
|
|
5074
|
-
transition: "endtransition",
|
|
5075
|
-
motion: "endmotion",
|
|
5076
|
-
scrollAnimate: "endscrollAnimate"
|
|
5077
|
-
};
|
|
5078
5257
|
function updateDiagnostics(document, diagnosticCollection) {
|
|
5079
5258
|
const config = vscode6.workspace.getConfiguration("stx.diagnostics");
|
|
5080
5259
|
const diagnosticsEnabled = config.get("enable", true);
|
|
@@ -5098,7 +5277,7 @@ function updateDiagnostics(document, diagnosticCollection) {
|
|
|
5098
5277
|
while (match !== null) {
|
|
5099
5278
|
const directiveName = match[1];
|
|
5100
5279
|
const position = match.index + 1;
|
|
5101
|
-
if (
|
|
5280
|
+
if (STX_DIRECTIVE_PAIRS[directiveName]) {
|
|
5102
5281
|
stack.push({
|
|
5103
5282
|
name: directiveName,
|
|
5104
5283
|
line: lineNum,
|
|
@@ -5107,14 +5286,14 @@ function updateDiagnostics(document, diagnosticCollection) {
|
|
|
5107
5286
|
} else {
|
|
5108
5287
|
const isEndDirective = directiveName.startsWith("end");
|
|
5109
5288
|
if (isEndDirective) {
|
|
5110
|
-
const openingName =
|
|
5289
|
+
const openingName = STX_OPENING_DIRECTIVE_BY_CLOSE.get(directiveName);
|
|
5111
5290
|
if (openingName && validateMismatched) {
|
|
5112
5291
|
if (stack.length > 0) {
|
|
5113
5292
|
const lastOpening = stack[stack.length - 1];
|
|
5114
5293
|
if (lastOpening.name === openingName) {
|
|
5115
5294
|
stack.pop();
|
|
5116
5295
|
} else {
|
|
5117
|
-
const diagnostic = new vscode6.Diagnostic(new vscode6.Range(new vscode6.Position(lineNum, position), new vscode6.Position(lineNum, position + directiveName.length)), `Mismatched directive. Expected @${
|
|
5296
|
+
const diagnostic = new vscode6.Diagnostic(new vscode6.Range(new vscode6.Position(lineNum, position), new vscode6.Position(lineNum, position + directiveName.length)), `Mismatched directive. Expected @${STX_DIRECTIVE_PAIRS[lastOpening.name]} but found @${directiveName}`, vscode6.DiagnosticSeverity.Error);
|
|
5118
5297
|
diagnostic.source = "stx";
|
|
5119
5298
|
diagnostics.push(diagnostic);
|
|
5120
5299
|
}
|
|
@@ -5135,7 +5314,7 @@ function updateDiagnostics(document, diagnosticCollection) {
|
|
|
5135
5314
|
}
|
|
5136
5315
|
if (validateUnclosed) {
|
|
5137
5316
|
for (const unclosed of stack) {
|
|
5138
|
-
const diagnostic = new vscode6.Diagnostic(new vscode6.Range(new vscode6.Position(unclosed.line, unclosed.character), new vscode6.Position(unclosed.line, unclosed.character + unclosed.name.length)), `Unclosed @${unclosed.name} directive. Expected @${
|
|
5317
|
+
const diagnostic = new vscode6.Diagnostic(new vscode6.Range(new vscode6.Position(unclosed.line, unclosed.character), new vscode6.Position(unclosed.line, unclosed.character + unclosed.name.length)), `Unclosed @${unclosed.name} directive. Expected @${STX_DIRECTIVE_PAIRS[unclosed.name]}`, vscode6.DiagnosticSeverity.Warning);
|
|
5139
5318
|
diagnostic.source = "stx";
|
|
5140
5319
|
diagnostics.push(diagnostic);
|
|
5141
5320
|
}
|
|
@@ -5149,38 +5328,22 @@ function updateDiagnostics(document, diagnosticCollection) {
|
|
|
5149
5328
|
diagnosticCollection.set(document.uri, diagnostics);
|
|
5150
5329
|
}
|
|
5151
5330
|
function validateTemplatePaths(document, diagnostics) {
|
|
5152
|
-
const workspaceFolder = vscode6.workspace.
|
|
5331
|
+
const workspaceFolder = vscode6.workspace.getWorkspaceFolder(document.uri);
|
|
5153
5332
|
if (!workspaceFolder) {
|
|
5154
5333
|
return;
|
|
5155
5334
|
}
|
|
5156
5335
|
const workspacePath = workspaceFolder.uri.fsPath;
|
|
5157
|
-
const templateDirs = [
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
"src/views",
|
|
5162
|
-
"src/templates",
|
|
5163
|
-
"app/views",
|
|
5164
|
-
"partials",
|
|
5165
|
-
"components",
|
|
5166
|
-
"layouts",
|
|
5167
|
-
"src/components",
|
|
5168
|
-
"app/components"
|
|
5169
|
-
];
|
|
5170
|
-
const pathDirectiveRegex = /@(include(?:If|When|Unless|First)?|component|webcomponent)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
5336
|
+
const templateDirs = [...new Set([
|
|
5337
|
+
...TEMPLATE_SEARCH_DIRECTORIES,
|
|
5338
|
+
...COMPONENT_SEARCH_DIRECTORIES
|
|
5339
|
+
])];
|
|
5171
5340
|
for (let lineNum = 0;lineNum < document.lineCount; lineNum++) {
|
|
5172
5341
|
const line = document.lineAt(lineNum);
|
|
5173
5342
|
const text = line.text;
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
|
|
5178
|
-
const directiveName = match[1];
|
|
5179
|
-
const templatePath = match[2];
|
|
5180
|
-
const pathStart = match.index + match[0].indexOf(templatePath);
|
|
5181
|
-
if (directiveName === "includeFirst") {
|
|
5182
|
-
continue;
|
|
5183
|
-
}
|
|
5343
|
+
if (/@includeFirst\s*\(/.test(text))
|
|
5344
|
+
continue;
|
|
5345
|
+
for (const reference of findTemplatePathReferences(text)) {
|
|
5346
|
+
const templatePath = reference.path;
|
|
5184
5347
|
let found = false;
|
|
5185
5348
|
for (const templateDir of templateDirs) {
|
|
5186
5349
|
const stxPath = path4.join(workspacePath, templateDir, `${templatePath}.stx`);
|
|
@@ -5200,12 +5363,11 @@ function validateTemplatePaths(document, diagnostics) {
|
|
|
5200
5363
|
}
|
|
5201
5364
|
}
|
|
5202
5365
|
if (!found) {
|
|
5203
|
-
const diagnostic = new vscode6.Diagnostic(new vscode6.Range(new vscode6.Position(lineNum,
|
|
5366
|
+
const diagnostic = new vscode6.Diagnostic(new vscode6.Range(new vscode6.Position(lineNum, reference.start), new vscode6.Position(lineNum, reference.end)), `Template file '${templatePath}' not found in any template directory`, vscode6.DiagnosticSeverity.Warning);
|
|
5204
5367
|
diagnostic.code = "template-not-found";
|
|
5205
5368
|
diagnostic.source = "stx";
|
|
5206
5369
|
diagnostics.push(diagnostic);
|
|
5207
5370
|
}
|
|
5208
|
-
match = pathDirectiveRegex.exec(text);
|
|
5209
5371
|
}
|
|
5210
5372
|
}
|
|
5211
5373
|
}
|
|
@@ -5270,20 +5432,13 @@ function createDocumentLinkProvider() {
|
|
|
5270
5432
|
const links = [];
|
|
5271
5433
|
for (let lineIndex = 0;lineIndex < document.lineCount; lineIndex++) {
|
|
5272
5434
|
const line = document.lineAt(lineIndex).text;
|
|
5273
|
-
const
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
const resolvedUri = resolveTemplatePath(document.uri, templatePath);
|
|
5281
|
-
if (resolvedUri) {
|
|
5282
|
-
const documentLink = new vscode7.DocumentLink(range, resolvedUri);
|
|
5283
|
-
documentLink.tooltip = `Open ${templatePath}`;
|
|
5284
|
-
links.push(documentLink);
|
|
5285
|
-
}
|
|
5286
|
-
}
|
|
5435
|
+
for (const reference of findTemplatePathReferences(line)) {
|
|
5436
|
+
const resolvedUri = resolveTemplatePath(document.uri, reference.path);
|
|
5437
|
+
if (resolvedUri) {
|
|
5438
|
+
const range = new vscode7.Range(lineIndex, reference.start, lineIndex, reference.end);
|
|
5439
|
+
const documentLink = new vscode7.DocumentLink(range, resolvedUri);
|
|
5440
|
+
documentLink.tooltip = `Open ${reference.path}`;
|
|
5441
|
+
links.push(documentLink);
|
|
5287
5442
|
}
|
|
5288
5443
|
}
|
|
5289
5444
|
}
|
|
@@ -5300,32 +5455,21 @@ function createPathCompletionProvider() {
|
|
|
5300
5455
|
provideCompletionItems(document, position, _token, _context) {
|
|
5301
5456
|
const line = document.lineAt(position.line).text;
|
|
5302
5457
|
const linePrefix = line.substring(0, position.character);
|
|
5303
|
-
const
|
|
5304
|
-
|
|
5305
|
-
if (!includeMatch && !componentMatch) {
|
|
5458
|
+
const pathContext = getTemplatePathCompletionContext(linePrefix);
|
|
5459
|
+
if (!pathContext) {
|
|
5306
5460
|
return;
|
|
5307
5461
|
}
|
|
5308
|
-
const currentPath =
|
|
5309
|
-
const isInclude =
|
|
5310
|
-
const workspaceFolder = vscode8.workspace.
|
|
5462
|
+
const currentPath = pathContext.path;
|
|
5463
|
+
const isInclude = pathContext.kind === "include";
|
|
5464
|
+
const workspaceFolder = vscode8.workspace.getWorkspaceFolder(document.uri);
|
|
5311
5465
|
if (!workspaceFolder) {
|
|
5312
5466
|
return;
|
|
5313
5467
|
}
|
|
5314
5468
|
const workspacePath = workspaceFolder.uri.fsPath;
|
|
5315
|
-
const templateDirs = [
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
"src/views",
|
|
5320
|
-
"src/templates",
|
|
5321
|
-
"app/views",
|
|
5322
|
-
"partials",
|
|
5323
|
-
"components",
|
|
5324
|
-
"layouts"
|
|
5325
|
-
];
|
|
5326
|
-
if (!isInclude) {
|
|
5327
|
-
templateDirs.push("src/components", "app/components", "ui", "src/ui");
|
|
5328
|
-
}
|
|
5469
|
+
const templateDirs = [...new Set([
|
|
5470
|
+
...TEMPLATE_SEARCH_DIRECTORIES.filter(Boolean),
|
|
5471
|
+
...!isInclude ? COMPONENT_SEARCH_DIRECTORIES : []
|
|
5472
|
+
])];
|
|
5329
5473
|
const completions = [];
|
|
5330
5474
|
let searchPath = workspacePath;
|
|
5331
5475
|
let searchRelative = "";
|
|
@@ -5402,6 +5546,22 @@ function createPathCompletionProvider() {
|
|
|
5402
5546
|
}
|
|
5403
5547
|
// ../vscode/src/providers/codeActionsProvider.ts
|
|
5404
5548
|
import * as vscode9 from "vscode";
|
|
5549
|
+
|
|
5550
|
+
// ../vscode/src/utils/directive-code-actions.ts
|
|
5551
|
+
function directiveDiagnosticAction(message) {
|
|
5552
|
+
const unclosed = message.match(/^Unclosed @\w+ directive\. Expected @(\w+)$/);
|
|
5553
|
+
if (unclosed)
|
|
5554
|
+
return { kind: "add-closing", directive: unclosed[1] };
|
|
5555
|
+
const mismatched = message.match(/^Mismatched directive\. Expected @(\w+) but found @\w+$/);
|
|
5556
|
+
if (mismatched)
|
|
5557
|
+
return { kind: "replace-closing", directive: mismatched[1] };
|
|
5558
|
+
const unexpected = message.match(/^Unexpected @(\w+)\. No matching opening directive found$/);
|
|
5559
|
+
if (unexpected)
|
|
5560
|
+
return { kind: "remove-closing", directive: unexpected[1] };
|
|
5561
|
+
return;
|
|
5562
|
+
}
|
|
5563
|
+
|
|
5564
|
+
// ../vscode/src/providers/codeActionsProvider.ts
|
|
5405
5565
|
function createCodeActionsProvider() {
|
|
5406
5566
|
return {
|
|
5407
5567
|
provideCodeActions(document, range, context, _token) {
|
|
@@ -5411,92 +5571,44 @@ function createCodeActionsProvider() {
|
|
|
5411
5571
|
return [];
|
|
5412
5572
|
}
|
|
5413
5573
|
const actions = [];
|
|
5414
|
-
const _directivePairs = {
|
|
5415
|
-
if: "endif",
|
|
5416
|
-
unless: "endunless",
|
|
5417
|
-
for: "endfor",
|
|
5418
|
-
foreach: "endforeach",
|
|
5419
|
-
forelse: "endforelse",
|
|
5420
|
-
while: "endwhile",
|
|
5421
|
-
switch: "endswitch",
|
|
5422
|
-
ts: "endts",
|
|
5423
|
-
js: "endjs",
|
|
5424
|
-
script: "endscript",
|
|
5425
|
-
css: "endcss",
|
|
5426
|
-
markdown: "endmarkdown",
|
|
5427
|
-
raw: "endraw",
|
|
5428
|
-
verbatim: "endverbatim",
|
|
5429
|
-
component: "endcomponent",
|
|
5430
|
-
slot: "endslot",
|
|
5431
|
-
webcomponent: "endwebcomponent",
|
|
5432
|
-
section: "endsection",
|
|
5433
|
-
push: "endpush",
|
|
5434
|
-
pushIf: "endpushIf",
|
|
5435
|
-
pushOnce: "endpushOnce",
|
|
5436
|
-
prepend: "endprepend",
|
|
5437
|
-
prependOnce: "endprependOnce",
|
|
5438
|
-
auth: "endauth",
|
|
5439
|
-
guest: "endguest",
|
|
5440
|
-
can: "endcan",
|
|
5441
|
-
cannot: "endcannot",
|
|
5442
|
-
env: "endenv",
|
|
5443
|
-
isset: "endisset",
|
|
5444
|
-
empty: "endempty",
|
|
5445
|
-
error: "enderror",
|
|
5446
|
-
once: "endonce",
|
|
5447
|
-
transition: "endtransition",
|
|
5448
|
-
motion: "endmotion",
|
|
5449
|
-
scrollAnimate: "endscrollAnimate"
|
|
5450
|
-
};
|
|
5451
5574
|
for (const diagnostic of context.diagnostics) {
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
insertLine = i - 1;
|
|
5465
|
-
break;
|
|
5466
|
-
}
|
|
5575
|
+
const diagnosticAction = directiveDiagnosticAction(diagnostic.message);
|
|
5576
|
+
if (diagnosticAction?.kind === "add-closing") {
|
|
5577
|
+
const endDirective = diagnosticAction.directive;
|
|
5578
|
+
const fix = new vscode9.CodeAction(`Add missing @${endDirective}`, vscode9.CodeActionKind.QuickFix);
|
|
5579
|
+
fix.diagnostics = [diagnostic];
|
|
5580
|
+
fix.isPreferred = true;
|
|
5581
|
+
let insertLine = document.lineCount - 1;
|
|
5582
|
+
for (let i = diagnostic.range.start.line + 1;i < document.lineCount; i++) {
|
|
5583
|
+
const line = document.lineAt(i).text.trim();
|
|
5584
|
+
if (line.match(/^@\w+/) && !line.startsWith(`@end`)) {
|
|
5585
|
+
insertLine = i - 1;
|
|
5586
|
+
break;
|
|
5467
5587
|
}
|
|
5468
|
-
const openingLine = document.lineAt(diagnostic.range.start.line);
|
|
5469
|
-
const indent = openingLine.text.match(/^\s*/)?.[0] || "";
|
|
5470
|
-
fix.edit = new vscode9.WorkspaceEdit;
|
|
5471
|
-
fix.edit.insert(document.uri, new vscode9.Position(insertLine + 1, 0), `${indent}@${endDirective}
|
|
5472
|
-
`);
|
|
5473
|
-
actions.push(fix);
|
|
5474
5588
|
}
|
|
5589
|
+
const openingLine = document.lineAt(diagnostic.range.start.line);
|
|
5590
|
+
const indent = openingLine.text.match(/^\s*/)?.[0] || "";
|
|
5591
|
+
fix.edit = new vscode9.WorkspaceEdit;
|
|
5592
|
+
fix.edit.insert(document.uri, new vscode9.Position(insertLine + 1, 0), `${indent}@${endDirective}
|
|
5593
|
+
`);
|
|
5594
|
+
actions.push(fix);
|
|
5475
5595
|
}
|
|
5476
|
-
if (
|
|
5477
|
-
const
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
fix.edit = new vscode9.WorkspaceEdit;
|
|
5485
|
-
fix.edit.replace(document.uri, diagnostic.range, expectedEnd);
|
|
5486
|
-
actions.push(fix);
|
|
5487
|
-
}
|
|
5596
|
+
if (diagnosticAction?.kind === "replace-closing") {
|
|
5597
|
+
const expectedEnd = diagnosticAction.directive;
|
|
5598
|
+
const fix = new vscode9.CodeAction(`Change to @${expectedEnd}`, vscode9.CodeActionKind.QuickFix);
|
|
5599
|
+
fix.diagnostics = [diagnostic];
|
|
5600
|
+
fix.isPreferred = true;
|
|
5601
|
+
fix.edit = new vscode9.WorkspaceEdit;
|
|
5602
|
+
fix.edit.replace(document.uri, diagnostic.range, expectedEnd);
|
|
5603
|
+
actions.push(fix);
|
|
5488
5604
|
}
|
|
5489
|
-
if (
|
|
5490
|
-
const
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
removeFix.edit = new vscode9.WorkspaceEdit;
|
|
5497
|
-
removeFix.edit.delete(document.uri, line.range);
|
|
5498
|
-
actions.push(removeFix);
|
|
5499
|
-
}
|
|
5605
|
+
if (diagnosticAction?.kind === "remove-closing") {
|
|
5606
|
+
const directiveName = diagnosticAction.directive;
|
|
5607
|
+
const removeFix = new vscode9.CodeAction(`Remove @${directiveName}`, vscode9.CodeActionKind.QuickFix);
|
|
5608
|
+
removeFix.diagnostics = [diagnostic];
|
|
5609
|
+
removeFix.edit = new vscode9.WorkspaceEdit;
|
|
5610
|
+
removeFix.edit.delete(document.uri, diagnostic.range.with(diagnostic.range.start.translate(0, -1), diagnostic.range.end));
|
|
5611
|
+
actions.push(removeFix);
|
|
5500
5612
|
}
|
|
5501
5613
|
}
|
|
5502
5614
|
const line = document.lineAt(range.start.line);
|
|
@@ -5544,43 +5656,6 @@ function createFoldingRangeProvider() {
|
|
|
5544
5656
|
return [];
|
|
5545
5657
|
}
|
|
5546
5658
|
const foldingRanges = [];
|
|
5547
|
-
const directivePairs = {
|
|
5548
|
-
if: "endif",
|
|
5549
|
-
unless: "endunless",
|
|
5550
|
-
for: "endfor",
|
|
5551
|
-
foreach: "endforeach",
|
|
5552
|
-
forelse: "endforelse",
|
|
5553
|
-
while: "endwhile",
|
|
5554
|
-
switch: "endswitch",
|
|
5555
|
-
ts: "endts",
|
|
5556
|
-
js: "endjs",
|
|
5557
|
-
script: "endscript",
|
|
5558
|
-
css: "endcss",
|
|
5559
|
-
markdown: "endmarkdown",
|
|
5560
|
-
raw: "endraw",
|
|
5561
|
-
verbatim: "endverbatim",
|
|
5562
|
-
component: "endcomponent",
|
|
5563
|
-
slot: "endslot",
|
|
5564
|
-
webcomponent: "endwebcomponent",
|
|
5565
|
-
section: "endsection",
|
|
5566
|
-
push: "endpush",
|
|
5567
|
-
pushIf: "endpushIf",
|
|
5568
|
-
pushOnce: "endpushOnce",
|
|
5569
|
-
prepend: "endprepend",
|
|
5570
|
-
prependOnce: "endprependOnce",
|
|
5571
|
-
auth: "endauth",
|
|
5572
|
-
guest: "endguest",
|
|
5573
|
-
can: "endcan",
|
|
5574
|
-
cannot: "endcannot",
|
|
5575
|
-
env: "endenv",
|
|
5576
|
-
isset: "endisset",
|
|
5577
|
-
empty: "endempty",
|
|
5578
|
-
error: "enderror",
|
|
5579
|
-
once: "endonce",
|
|
5580
|
-
transition: "endtransition",
|
|
5581
|
-
motion: "endmotion",
|
|
5582
|
-
scrollAnimate: "endscrollAnimate"
|
|
5583
|
-
};
|
|
5584
5659
|
const stack = [];
|
|
5585
5660
|
const directiveRegex = /@(\w+)(?:\(|$|\s)/g;
|
|
5586
5661
|
function getFoldingKind(directiveName) {
|
|
@@ -5600,7 +5675,7 @@ function createFoldingRangeProvider() {
|
|
|
5600
5675
|
match = directiveRegex.exec(text);
|
|
5601
5676
|
while (match !== null) {
|
|
5602
5677
|
const directiveName = match[1];
|
|
5603
|
-
if (
|
|
5678
|
+
if (STX_DIRECTIVE_PAIRS[directiveName]) {
|
|
5604
5679
|
stack.push({
|
|
5605
5680
|
name: directiveName,
|
|
5606
5681
|
line: lineNum,
|
|
@@ -5609,7 +5684,7 @@ function createFoldingRangeProvider() {
|
|
|
5609
5684
|
} else {
|
|
5610
5685
|
const isEndDirective = directiveName.startsWith("end");
|
|
5611
5686
|
if (isEndDirective) {
|
|
5612
|
-
const openingName =
|
|
5687
|
+
const openingName = STX_OPENING_DIRECTIVE_BY_CLOSE.get(directiveName);
|
|
5613
5688
|
if (openingName && stack.length > 0) {
|
|
5614
5689
|
const lastOpening = stack[stack.length - 1];
|
|
5615
5690
|
if (lastOpening.name === openingName) {
|
|
@@ -6766,12 +6841,93 @@ function findForeachDeclarationForVariable(document, currentLine, variableName)
|
|
|
6766
6841
|
return null;
|
|
6767
6842
|
}
|
|
6768
6843
|
// ../vscode/src/language.ts
|
|
6844
|
+
import * as path8 from "node:path";
|
|
6845
|
+
import * as vscode16 from "vscode";
|
|
6846
|
+
|
|
6847
|
+
// ../vscode/src/commands/extractToComponent.ts
|
|
6848
|
+
import * as path7 from "node:path";
|
|
6849
|
+
import * as vscode14 from "vscode";
|
|
6850
|
+
|
|
6851
|
+
// ../vscode/src/commands/extract-component.ts
|
|
6769
6852
|
import * as path6 from "node:path";
|
|
6770
|
-
|
|
6853
|
+
function normalizeComponentName(input) {
|
|
6854
|
+
const trimmed = input.trim();
|
|
6855
|
+
if (!trimmed || !/^[A-Za-z][A-Za-z0-9 _-]*$/.test(trimmed))
|
|
6856
|
+
return;
|
|
6857
|
+
if (/^[A-Z][A-Za-z0-9]*$/.test(trimmed))
|
|
6858
|
+
return trimmed;
|
|
6859
|
+
const words = trimmed.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[\s_-]+/).filter(Boolean);
|
|
6860
|
+
return words.map((word) => word[0].toUpperCase() + word.slice(1)).join("");
|
|
6861
|
+
}
|
|
6862
|
+
function extractedComponentContent(selection) {
|
|
6863
|
+
const lines = selection.replace(/\r\n/g, `
|
|
6864
|
+
`).split(`
|
|
6865
|
+
`);
|
|
6866
|
+
while (lines[0]?.trim() === "")
|
|
6867
|
+
lines.shift();
|
|
6868
|
+
while (lines[lines.length - 1]?.trim() === "")
|
|
6869
|
+
lines.pop();
|
|
6870
|
+
const indents = lines.filter((line) => line.trim()).map((line) => line.match(/^\s*/)?.[0].length ?? 0);
|
|
6871
|
+
const commonIndent = indents.length ? Math.min(...indents) : 0;
|
|
6872
|
+
return `${lines.map((line) => line.slice(commonIndent)).join(`
|
|
6873
|
+
`)}
|
|
6874
|
+
`;
|
|
6875
|
+
}
|
|
6876
|
+
function componentDirectoryForDocument(workspacePath, documentPath) {
|
|
6877
|
+
const relative2 = path6.relative(workspacePath, documentPath);
|
|
6878
|
+
const segments = relative2.split(path6.sep);
|
|
6879
|
+
if (segments[0] === "resources" && segments[1] === "views")
|
|
6880
|
+
return path6.join(workspacePath, "resources", "views", "components");
|
|
6881
|
+
if (segments[0] === "src")
|
|
6882
|
+
return path6.join(workspacePath, "src", "components");
|
|
6883
|
+
return path6.join(workspacePath, "components");
|
|
6884
|
+
}
|
|
6885
|
+
|
|
6886
|
+
// ../vscode/src/commands/extractToComponent.ts
|
|
6887
|
+
function registerExtractToComponentCommand() {
|
|
6888
|
+
return vscode14.commands.registerCommand("stx.extractToComponent", async (document, range) => {
|
|
6889
|
+
const selection = document.getText(range);
|
|
6890
|
+
if (!selection.trim())
|
|
6891
|
+
return;
|
|
6892
|
+
const requestedName = await vscode14.window.showInputBox({
|
|
6893
|
+
prompt: "Name the extracted stx component",
|
|
6894
|
+
placeHolder: "UserCard",
|
|
6895
|
+
validateInput: (value) => normalizeComponentName(value) ? undefined : "Use a component name beginning with a letter"
|
|
6896
|
+
});
|
|
6897
|
+
if (!requestedName)
|
|
6898
|
+
return;
|
|
6899
|
+
const componentName = normalizeComponentName(requestedName);
|
|
6900
|
+
if (!componentName)
|
|
6901
|
+
return;
|
|
6902
|
+
const workspaceFolder = vscode14.workspace.getWorkspaceFolder(document.uri);
|
|
6903
|
+
if (!workspaceFolder) {
|
|
6904
|
+
await vscode14.window.showErrorMessage("Open the stx file in a workspace before extracting a component.");
|
|
6905
|
+
return;
|
|
6906
|
+
}
|
|
6907
|
+
const componentDirectory = componentDirectoryForDocument(workspaceFolder.uri.fsPath, document.uri.fsPath);
|
|
6908
|
+
const componentUri = vscode14.Uri.file(path7.join(componentDirectory, `${componentName}.stx`));
|
|
6909
|
+
try {
|
|
6910
|
+
await vscode14.workspace.fs.stat(componentUri);
|
|
6911
|
+
await vscode14.window.showErrorMessage(`Component ${componentName}.stx already exists.`);
|
|
6912
|
+
return;
|
|
6913
|
+
} catch {}
|
|
6914
|
+
await vscode14.workspace.fs.createDirectory(vscode14.Uri.file(componentDirectory));
|
|
6915
|
+
const edit = new vscode14.WorkspaceEdit;
|
|
6916
|
+
edit.createFile(componentUri);
|
|
6917
|
+
edit.insert(componentUri, new vscode14.Position(0, 0), extractedComponentContent(selection));
|
|
6918
|
+
edit.replace(document.uri, range, `<${componentName} />`);
|
|
6919
|
+
if (!await vscode14.workspace.applyEdit(edit)) {
|
|
6920
|
+
await vscode14.window.showErrorMessage(`Could not extract ${componentName}.stx.`);
|
|
6921
|
+
return;
|
|
6922
|
+
}
|
|
6923
|
+
const componentDocument = await vscode14.workspace.openTextDocument(componentUri);
|
|
6924
|
+
await vscode14.window.showTextDocument(componentDocument);
|
|
6925
|
+
});
|
|
6926
|
+
}
|
|
6771
6927
|
|
|
6772
6928
|
// ../vscode/src/snippets.ts
|
|
6773
6929
|
import * as fs5 from "node:fs";
|
|
6774
|
-
import * as
|
|
6930
|
+
import * as vscode15 from "vscode";
|
|
6775
6931
|
function snippetCompletionItems(file) {
|
|
6776
6932
|
let definitions;
|
|
6777
6933
|
try {
|
|
@@ -6786,10 +6942,10 @@ function snippetCompletionItems(file) {
|
|
|
6786
6942
|
const body = Array.isArray(snippet.body) ? snippet.body.join(`
|
|
6787
6943
|
`) : snippet.body;
|
|
6788
6944
|
for (const prefix of prefixes) {
|
|
6789
|
-
const item = new
|
|
6790
|
-
item.insertText = new
|
|
6945
|
+
const item = new vscode15.CompletionItem(prefix, vscode15.CompletionItemKind.Snippet);
|
|
6946
|
+
item.insertText = new vscode15.SnippetString(body);
|
|
6791
6947
|
item.detail = snippet.description ?? name;
|
|
6792
|
-
item.documentation = new
|
|
6948
|
+
item.documentation = new vscode15.MarkdownString().appendCodeblock(body, "stx");
|
|
6793
6949
|
items.push(item);
|
|
6794
6950
|
}
|
|
6795
6951
|
}
|
|
@@ -6797,7 +6953,7 @@ function snippetCompletionItems(file) {
|
|
|
6797
6953
|
}
|
|
6798
6954
|
function registerSnippetCompletions(file) {
|
|
6799
6955
|
const items = snippetCompletionItems(file);
|
|
6800
|
-
return
|
|
6956
|
+
return vscode15.languages.registerCompletionItemProvider("stx", {
|
|
6801
6957
|
provideCompletionItems: () => items
|
|
6802
6958
|
});
|
|
6803
6959
|
}
|
|
@@ -6816,32 +6972,32 @@ async function activateStxLanguage(context, options) {
|
|
|
6816
6972
|
});
|
|
6817
6973
|
componentRegistry.watchWorkspace(context);
|
|
6818
6974
|
if (options.snippets)
|
|
6819
|
-
context.subscriptions.push(registerSnippetCompletions(
|
|
6820
|
-
|
|
6975
|
+
context.subscriptions.push(registerSnippetCompletions(path8.join(options.assetsPath, "snippets", "stx.json")));
|
|
6976
|
+
vscode16.workspace.textDocuments.forEach((document) => {
|
|
6821
6977
|
if (document.fileName.endsWith(".stx") && document.languageId !== "stx") {
|
|
6822
|
-
|
|
6978
|
+
vscode16.languages.setTextDocumentLanguage(document, "stx").then(() => console.log(`Set language ID for ${document.fileName} to stx`));
|
|
6823
6979
|
}
|
|
6824
6980
|
});
|
|
6825
|
-
const hoverProvider =
|
|
6826
|
-
const definitionProvider =
|
|
6827
|
-
const documentLinkProvider =
|
|
6981
|
+
const hoverProvider = vscode16.languages.registerHoverProvider("stx", createHoverProvider(virtualTsDocumentProvider));
|
|
6982
|
+
const definitionProvider = vscode16.languages.registerDefinitionProvider("stx", createDefinitionProvider(virtualTsDocumentProvider));
|
|
6983
|
+
const documentLinkProvider = vscode16.languages.registerDocumentLinkProvider("stx", createDocumentLinkProvider());
|
|
6828
6984
|
const completionProvider = createCompletionProvider();
|
|
6829
|
-
const
|
|
6830
|
-
const
|
|
6831
|
-
|
|
6832
|
-
context.subscriptions.push(vscode15.workspace.registerTextDocumentContentProvider("stx-ts", virtualTsDocumentProvider));
|
|
6985
|
+
const languageCompletionProvider = vscode16.languages.registerCompletionItemProvider("stx", completionProvider, "@", ":", "-", "'", '"', "`", ",", ".");
|
|
6986
|
+
const pathCompletionProvider = vscode16.languages.registerCompletionItemProvider("stx", createPathCompletionProvider(), "/", "'", '"');
|
|
6987
|
+
context.subscriptions.push(vscode16.workspace.registerTextDocumentContentProvider("stx-ts", virtualTsDocumentProvider));
|
|
6833
6988
|
createDiagnosticsProvider(context);
|
|
6834
|
-
const codeActionsProvider =
|
|
6989
|
+
const codeActionsProvider = vscode16.languages.registerCodeActionsProvider("stx", createCodeActionsProvider(), {
|
|
6835
6990
|
providedCodeActionKinds: [
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6991
|
+
vscode16.CodeActionKind.QuickFix,
|
|
6992
|
+
vscode16.CodeActionKind.RefactorRewrite,
|
|
6993
|
+
vscode16.CodeActionKind.RefactorExtract
|
|
6839
6994
|
]
|
|
6840
6995
|
});
|
|
6841
|
-
const
|
|
6842
|
-
const
|
|
6996
|
+
const extractToComponentCommand = registerExtractToComponentCommand();
|
|
6997
|
+
const foldingRangeProvider = vscode16.languages.registerFoldingRangeProvider("stx", createFoldingRangeProvider());
|
|
6998
|
+
const semanticTokensProvider = vscode16.languages.registerDocumentSemanticTokensProvider("stx", createSemanticTokensProvider(), legend);
|
|
6843
6999
|
let updateTimeout;
|
|
6844
|
-
const documentChangeListener =
|
|
7000
|
+
const documentChangeListener = vscode16.workspace.onDidChangeTextDocument((event) => {
|
|
6845
7001
|
if (event.document.languageId === "stx" || event.document.languageId === "markdown" && event.document.fileName.endsWith(".md")) {
|
|
6846
7002
|
clearTimeout(updateTimeout);
|
|
6847
7003
|
updateTimeout = setTimeout(() => {
|
|
@@ -6849,7 +7005,7 @@ async function activateStxLanguage(context, options) {
|
|
|
6849
7005
|
}, 150);
|
|
6850
7006
|
}
|
|
6851
7007
|
});
|
|
6852
|
-
const documentOpenListener =
|
|
7008
|
+
const documentOpenListener = vscode16.workspace.onDidOpenTextDocument(async (document) => {
|
|
6853
7009
|
const isStx = document.languageId === "stx" || document.fileName.endsWith(".stx");
|
|
6854
7010
|
const isMarkdown = document.languageId === "markdown" && document.fileName.endsWith(".md");
|
|
6855
7011
|
if (!isStx && !isMarkdown)
|
|
@@ -6857,7 +7013,7 @@ async function activateStxLanguage(context, options) {
|
|
|
6857
7013
|
virtualTsDocumentProvider.trackDocument(document);
|
|
6858
7014
|
if (isStx && document.languageId !== "stx") {
|
|
6859
7015
|
try {
|
|
6860
|
-
await
|
|
7016
|
+
await vscode16.languages.setTextDocumentLanguage(document, "stx");
|
|
6861
7017
|
} catch {}
|
|
6862
7018
|
}
|
|
6863
7019
|
const virtualUri = document.uri.with({
|
|
@@ -6865,12 +7021,12 @@ async function activateStxLanguage(context, options) {
|
|
|
6865
7021
|
path: `${document.uri.path}.ts`
|
|
6866
7022
|
});
|
|
6867
7023
|
try {
|
|
6868
|
-
await
|
|
7024
|
+
await vscode16.workspace.openTextDocument(virtualUri);
|
|
6869
7025
|
} catch (error) {
|
|
6870
7026
|
console.error("Failed to open virtual TypeScript document:", error);
|
|
6871
7027
|
}
|
|
6872
7028
|
});
|
|
6873
|
-
|
|
7029
|
+
vscode16.workspace.textDocuments.forEach((document) => {
|
|
6874
7030
|
if (document.languageId === "stx" || document.fileName.endsWith(".stx")) {
|
|
6875
7031
|
virtualTsDocumentProvider.trackDocument(document);
|
|
6876
7032
|
}
|
|
@@ -6878,8 +7034,8 @@ async function activateStxLanguage(context, options) {
|
|
|
6878
7034
|
virtualTsDocumentProvider.trackDocument(document);
|
|
6879
7035
|
}
|
|
6880
7036
|
});
|
|
6881
|
-
context.subscriptions.push(documentChangeListener, documentOpenListener, hoverProvider, definitionProvider, documentLinkProvider,
|
|
6882
|
-
const utilityClassesEnabled =
|
|
7037
|
+
context.subscriptions.push(documentChangeListener, documentOpenListener, hoverProvider, definitionProvider, documentLinkProvider, languageCompletionProvider, pathCompletionProvider, codeActionsProvider, extractToComponentCommand, foldingRangeProvider, semanticTokensProvider);
|
|
7038
|
+
const utilityClassesEnabled = vscode16.workspace.getConfiguration("stx.utilityClasses").get("enable", true);
|
|
6883
7039
|
if (utilityClassesEnabled) {
|
|
6884
7040
|
try {
|
|
6885
7041
|
await Promise.resolve().then(() => init_ts_css());
|
|
@@ -6887,7 +7043,7 @@ async function activateStxLanguage(context, options) {
|
|
|
6887
7043
|
console.log("stx Extension - Css utility class features activated");
|
|
6888
7044
|
} catch (error) {
|
|
6889
7045
|
console.error("stx Extension - Failed to activate Css features:", error);
|
|
6890
|
-
|
|
7046
|
+
vscode16.window.showErrorMessage(`Failed to activate Css: ${error}`);
|
|
6891
7047
|
}
|
|
6892
7048
|
}
|
|
6893
7049
|
console.log("stx language support activated (with Markdown frontmatter support)");
|
|
@@ -6897,8 +7053,8 @@ function deactivateStxLanguage() {
|
|
|
6897
7053
|
console.log("stx language support deactivated");
|
|
6898
7054
|
}
|
|
6899
7055
|
// ../vscode/src/extension.ts
|
|
6900
|
-
import * as
|
|
6901
|
-
import * as
|
|
7056
|
+
import * as path9 from "node:path";
|
|
7057
|
+
import * as vscode17 from "vscode";
|
|
6902
7058
|
|
|
6903
7059
|
// ../vscode/src/stand-down.ts
|
|
6904
7060
|
async function stacksProvidesStx(api) {
|
|
@@ -6940,15 +7096,15 @@ async function configureTypeScriptPlugin(api, subscriptions) {
|
|
|
6940
7096
|
|
|
6941
7097
|
// ../vscode/src/extension.ts
|
|
6942
7098
|
async function activate(context) {
|
|
6943
|
-
configureTypeScriptPlugin(
|
|
7099
|
+
configureTypeScriptPlugin(vscode17, context.subscriptions).catch((error) => {
|
|
6944
7100
|
console.error("stx Extension - could not configure the TypeScript plugin:", error);
|
|
6945
7101
|
});
|
|
6946
|
-
if (await stacksProvidesStx(
|
|
7102
|
+
if (await stacksProvidesStx(vscode17)) {
|
|
6947
7103
|
console.log(`stx Extension - ${STACKS_EXTENSION_ID} provides stx support in this window; not registering it twice`);
|
|
6948
7104
|
return;
|
|
6949
7105
|
}
|
|
6950
7106
|
await activateStxLanguage(context, {
|
|
6951
|
-
assetsPath:
|
|
7107
|
+
assetsPath: path9.join(context.extensionPath, "src"),
|
|
6952
7108
|
snippets: false
|
|
6953
7109
|
});
|
|
6954
7110
|
}
|
|
@@ -6961,6 +7117,9 @@ export {
|
|
|
6961
7117
|
DEFAULT_TRANSITION_OPTIONS,
|
|
6962
7118
|
PropsTypeExtractor,
|
|
6963
7119
|
STACKS_EXTENSION_ID,
|
|
7120
|
+
STX_ATTRIBUTE_DIRECTIVES,
|
|
7121
|
+
STX_DIRECTIVES,
|
|
7122
|
+
STX_DIRECTIVE_PAIRS,
|
|
6964
7123
|
STX_EXTENSION_ID,
|
|
6965
7124
|
TS_PLUGIN_NAME,
|
|
6966
7125
|
TS_PLUGIN_SETTINGS,
|
|
@@ -7002,6 +7161,10 @@ export {
|
|
|
7002
7161
|
formatJSDoc,
|
|
7003
7162
|
getClassAtPosition,
|
|
7004
7163
|
getDefaultConfig as getCssDefaultConfig,
|
|
7164
|
+
getStxAttributeAtOffset,
|
|
7165
|
+
getStxAttributeCompletionContext,
|
|
7166
|
+
getStxAttributeDefinition,
|
|
7167
|
+
getStxDirectiveAtOffset,
|
|
7005
7168
|
getTemplatePathRange,
|
|
7006
7169
|
isColorClass,
|
|
7007
7170
|
isCssClassName,
|
|
@@ -7017,6 +7180,7 @@ export {
|
|
|
7017
7180
|
snippetCompletionItems,
|
|
7018
7181
|
sortClasses,
|
|
7019
7182
|
stacksProvidesStx,
|
|
7183
|
+
stxSnippetPreview,
|
|
7020
7184
|
tokenModifiers,
|
|
7021
7185
|
tokenTypes
|
|
7022
7186
|
};
|