arcane-os 0.5.12 → 0.5.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/browser-runtime/ai/browser-wasm-llm-provider.mjs +11 -10
- package/browser-runtime/ai/browser-wllama-runtime.mjs +2 -1
- package/browser-runtime/ai/model-controller.mjs +6 -5
- package/browser-runtime/ai/speech-worker-client.mjs +45 -3
- package/browser-runtime/event-manager.mjs +2 -1
- package/browser-runtime/logging.mjs +58 -0
- package/docs/reference/README.md +8 -7
- package/docs/reference/ai/browser-speech.md +46 -1
- package/docs/reference/asset-versioning.md +69 -0
- package/docs/reference/inventory/package-api.json +30 -2
- package/docs/reference/runtime-modules.md +18 -0
- package/docs/reference/sdk-api.md +94 -8
- package/package.json +3 -2
- package/runtime/arcane/components/app-bar.html +3 -1
- package/runtime/arcane/components/calculator.html +1 -1
- package/runtime/arcane/components/chart.html +2 -7
- package/runtime/arcane/components/chat.html +22 -20
- package/runtime/arcane/components/dashboard-config.html +6 -9
- package/runtime/arcane/components/data-maintenance.html +4 -2
- package/runtime/arcane/components/data-view.html +3 -1
- package/runtime/arcane/components/directory-picker.html +3 -1
- package/runtime/arcane/components/file-manager.html +17 -15
- package/runtime/arcane/components/header.html +5 -3
- package/runtime/arcane/components/markdown-document.html +4 -7
- package/runtime/arcane/components/markdown-editor.html +6 -9
- package/runtime/arcane/components/media-embed.html +1 -1
- package/runtime/arcane/components/modal.html +3 -1
- package/runtime/arcane/components/screen-capture.html +4 -2
- package/runtime/arcane/components/speech.html +10 -8
- package/runtime/arcane/components/table.html +3 -1
- package/runtime/arcane/components/voice-transcription.html +12 -15
- package/runtime/arcane/entities/Chat.js +5 -4
- package/runtime/arcane/entities/User.js +2 -1
- package/runtime/arcane/modules/AI.js +442 -292
- package/runtime/arcane/modules/AIProviderRuntime.js +359 -82
- package/runtime/arcane/modules/CommunicationAppController.js +2 -1
- package/runtime/arcane/modules/ComponentContracts.js +3 -2
- package/runtime/arcane/modules/ConversationTimebox.js +2 -1
- package/runtime/arcane/modules/DBOPFS.js +5 -4
- package/runtime/arcane/modules/Errors.js +3 -14
- package/runtime/arcane/modules/HTMLImport.js +188 -16
- package/runtime/arcane/modules/LocalAIReadinessController.js +2 -1
- package/runtime/arcane/modules/MD.js +3 -2
- package/runtime/arcane/modules/MailOutbox.mjs +2 -1
- package/runtime/arcane/modules/PersistentAIChatSession.js +2 -1
- package/runtime/arcane/modules/ScreenCapture.js +2 -1
- package/runtime/arcane/modules/ThemeBootstrap.js +3 -2
- package/runtime/arcane/modules/ToolCallRouter.js +2 -1
- package/src/dev-server.mjs +72 -5
- package/src/import-map.mjs +603 -16
- package/src/installed-sdk-runtime.mjs +1 -0
- package/src/packager/core.mjs +60 -1
- package/src/workspace-runtime.mjs +19 -7
package/src/import-map.mjs
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {lstat,mkdir,readFile as readFileFromDisk,readdir,realpath,writeFile} from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import {pathToFileURL} from 'node:url';
|
|
4
|
+
import {SDK_VERSION} from './constants.mjs';
|
|
4
5
|
|
|
5
6
|
export const IMPORT_MAP_RELATIVE_PATH='modules/arcane.importmap.json';
|
|
6
7
|
export const MANAGED_IMPORT_MAP_ATTRIBUTE='data-arcane-import-map';
|
|
7
8
|
|
|
8
9
|
const JAVASCRIPT_EXTENSION=/\.(?:js|mjs)$/u;
|
|
10
|
+
const RESOURCE_EXTENSION=/\.(?:m?js|html?|css|wasm|svg|png|gif|jpe?g|webp|avif|ico|bmp|woff2?|ttf|otf|eot|mp3|wav|ogg|oga|opus|m4a|mp4|webm|ogv|vtt)(?:[?#]|$)/iu;
|
|
9
11
|
const PERSISTENT_CHAT_IMPORT='#arcane/persistent-ai-chat-session';
|
|
10
12
|
const PERSISTENT_CHAT_MODULE='modules/PersistentAIChatSession.js';
|
|
11
13
|
const SDK_BROWSER_ENTRY='sdk/event-manager.mjs';
|
|
@@ -17,6 +19,7 @@ const STATIC_RUNTIME_PACKAGE_IMPORTS=new Map([
|
|
|
17
19
|
]);
|
|
18
20
|
const SDK_BROWSER_SELF_IMPORTS=new Map([
|
|
19
21
|
['arcane-os/event-manager',SDK_BROWSER_ENTRY],
|
|
22
|
+
['arcane-os/logging','sdk/logging.mjs'],
|
|
20
23
|
['arcane-os/ai/browser-wasm',SDK_BROWSER_AI_ENTRY],
|
|
21
24
|
['arcane-os/ai/browser-speech',SDK_BROWSER_SPEECH_ENTRY]
|
|
22
25
|
]);
|
|
@@ -646,6 +649,7 @@ function tokenize(source){
|
|
|
646
649
|
function matchingToken(tokens,start,opening,closing){
|
|
647
650
|
let depth=0;
|
|
648
651
|
for(let index=start;index<tokens.length;index+=1){
|
|
652
|
+
if(tokens[index].type!=='punctuator')continue;
|
|
649
653
|
if(tokens[index].value===opening)depth+=1;
|
|
650
654
|
else if(tokens[index].value===closing){
|
|
651
655
|
depth-=1;
|
|
@@ -691,6 +695,7 @@ function topLevelCommas(tokens,start,end){
|
|
|
691
695
|
const commas=[];
|
|
692
696
|
const depths={parenthesis:0,bracket:0,brace:0};
|
|
693
697
|
for(let index=start;index<end;index+=1){
|
|
698
|
+
if(tokens[index].type!=='punctuator')continue;
|
|
694
699
|
const value=tokens[index].value;
|
|
695
700
|
if(value==='(')depths.parenthesis+=1;
|
|
696
701
|
else if(value===')'&&depths.parenthesis>0)depths.parenthesis-=1;
|
|
@@ -711,7 +716,10 @@ function importRecord(kind,token){
|
|
|
711
716
|
|
|
712
717
|
export function scanModuleImports(source,{importer='<module>'}={}){
|
|
713
718
|
if(typeof source!=='string')throw new TypeError('scanModuleImports source must be a string.');
|
|
714
|
-
|
|
719
|
+
return moduleImportsFromTokens(tokenize(source),importer);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function moduleImportsFromTokens(tokens,importer){
|
|
715
723
|
const imports=[];
|
|
716
724
|
let hasModuleSyntax=false;
|
|
717
725
|
for(let index=0;index<tokens.length;index+=1){
|
|
@@ -784,10 +792,405 @@ export function scanModuleImports(source,{importer='<module>'}={}){
|
|
|
784
792
|
};
|
|
785
793
|
}
|
|
786
794
|
|
|
795
|
+
export function versionAssetUrl(value,version=SDK_VERSION){
|
|
796
|
+
if(typeof value!=='string')return value;
|
|
797
|
+
return applyReferenceEdits(value,assetUrlVersionEdits(value,version));
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
function assetUrlVersionEdits(value,version){
|
|
801
|
+
if(typeof value!=='string'||!value||!version||value.startsWith('#')
|
|
802
|
+
||value.startsWith('//')||/^[A-Za-z][A-Za-z0-9+.-]*:/u.test(value)
|
|
803
|
+
||/^\s/u.test(value))return [];
|
|
804
|
+
const fragmentStart=value.indexOf('#');
|
|
805
|
+
const address=fragmentStart<0?value:value.slice(0,fragmentStart);
|
|
806
|
+
const queryStart=address.indexOf('?');
|
|
807
|
+
const pathname=queryStart<0?address:address.slice(0,queryStart);
|
|
808
|
+
if(!pathname)return [];
|
|
809
|
+
const versionValue=encodeURIComponent(String(version));
|
|
810
|
+
if(queryStart<0)return [{start:address.length,end:address.length,value:`?arcaneVersion=${versionValue}`}];
|
|
811
|
+
const query=address.slice(queryStart+1);
|
|
812
|
+
const edits=[];
|
|
813
|
+
let offset=queryStart+1;
|
|
814
|
+
for(const parameter of query.split('&')){
|
|
815
|
+
const equals=parameter.indexOf('=');
|
|
816
|
+
const key=equals<0?parameter:parameter.slice(0,equals);
|
|
817
|
+
let decodedKey=key;
|
|
818
|
+
try{decodedKey=decodeURIComponent(key.replaceAll('+',' '));}
|
|
819
|
+
catch{decodedKey=key;}
|
|
820
|
+
if(decodedKey==='arcaneVersion'){
|
|
821
|
+
edits.push({
|
|
822
|
+
start:offset+(equals<0?parameter.length:equals+1),
|
|
823
|
+
end:offset+parameter.length,
|
|
824
|
+
value:`${equals<0?'=':''}${versionValue}`
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
offset+=parameter.length+1;
|
|
828
|
+
}
|
|
829
|
+
if(edits.length===0)edits.push({
|
|
830
|
+
start:address.length,
|
|
831
|
+
end:address.length,
|
|
832
|
+
value:`${query&&!query.endsWith('&')?'&':''}arcaneVersion=${versionValue}`
|
|
833
|
+
});
|
|
834
|
+
return edits;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
function applyReferenceEdits(source,edits){
|
|
838
|
+
let result=source;
|
|
839
|
+
for(const edit of edits.sort(function descendingReferenceOffset(left,right){
|
|
840
|
+
return right.start-left.start;
|
|
841
|
+
})){
|
|
842
|
+
result=result.slice(0,edit.start)+edit.value+result.slice(edit.end);
|
|
843
|
+
}
|
|
844
|
+
return result;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
function stringReferenceEdit(source,token,version,urlEdits=assetUrlVersionEdits(token.value,version)){
|
|
848
|
+
if(urlEdits.length===0)return null;
|
|
849
|
+
const quote=source[token.start];
|
|
850
|
+
const positions=[];
|
|
851
|
+
let cursor=token.start+1;
|
|
852
|
+
while(cursor<token.end-1){
|
|
853
|
+
const start=cursor;
|
|
854
|
+
if(source[cursor]==='\\'){
|
|
855
|
+
const decoded=decodedEscape(source,cursor+1);
|
|
856
|
+
for(let index=0;index<decoded.value.length;index+=1)positions.push(start-token.start);
|
|
857
|
+
cursor=decoded.next;
|
|
858
|
+
}else{
|
|
859
|
+
positions.push(cursor-token.start);
|
|
860
|
+
cursor+=1;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
positions.push(token.end-token.start-1);
|
|
864
|
+
const edits=urlEdits.map(function authoredStringReference(edit){
|
|
865
|
+
return {
|
|
866
|
+
start:positions[edit.start],
|
|
867
|
+
end:positions[edit.end],
|
|
868
|
+
value:edit.value.replaceAll('\\','\\\\').replaceAll(quote,`\\${quote}`)
|
|
869
|
+
};
|
|
870
|
+
});
|
|
871
|
+
const original=source.slice(token.start,token.end);
|
|
872
|
+
const value=applyReferenceEdits(original,edits);
|
|
873
|
+
return value===original?null:{start:token.start,end:token.end,value};
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
function callArgumentTokens(tokens,opening){
|
|
877
|
+
const closing=matchingToken(tokens,opening,'(',')');
|
|
878
|
+
if(closing<0)return [];
|
|
879
|
+
const separators=topLevelCommas(tokens,opening+1,closing);
|
|
880
|
+
const boundaries=[opening,...separators,closing];
|
|
881
|
+
const argumentsList=[];
|
|
882
|
+
for(let index=0;index<boundaries.length-1;index+=1){
|
|
883
|
+
argumentsList.push(tokens.slice(boundaries[index]+1,boundaries[index+1]));
|
|
884
|
+
}
|
|
885
|
+
return argumentsList;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
function literalExpressionResults(tokens){
|
|
889
|
+
if(tokens.length===1&&tokens[0].type==='string')return tokens;
|
|
890
|
+
if(tokens[0]?.value==='('&&matchingToken(tokens,0,'(',')')===tokens.length-1){
|
|
891
|
+
return literalExpressionResults(tokens.slice(1,-1));
|
|
892
|
+
}
|
|
893
|
+
let depth=0;
|
|
894
|
+
let conditional=-1;
|
|
895
|
+
let nestedConditionals=0;
|
|
896
|
+
for(let index=0;index<tokens.length;index+=1){
|
|
897
|
+
if(tokens[index].type!=='punctuator')continue;
|
|
898
|
+
const value=tokens[index].value;
|
|
899
|
+
if(['(','[','{'].includes(value)){depth+=1;continue;}
|
|
900
|
+
if([')',']','}'].includes(value)){depth-=1;continue;}
|
|
901
|
+
if(depth!==0)continue;
|
|
902
|
+
if(value==='?'){
|
|
903
|
+
if(conditional<0)conditional=index;
|
|
904
|
+
else nestedConditionals+=1;
|
|
905
|
+
}else if(value===':'&&conditional>=0){
|
|
906
|
+
if(nestedConditionals>0){nestedConditionals-=1;continue;}
|
|
907
|
+
return [
|
|
908
|
+
...literalExpressionResults(tokens.slice(conditional+1,index)),
|
|
909
|
+
...literalExpressionResults(tokens.slice(index+1))
|
|
910
|
+
];
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
return [];
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
function globalResourceCallee(tokens,index){
|
|
917
|
+
if(!identifierIsProperty(tokens,index))return index;
|
|
918
|
+
if((tokens[index-1]?.value==='.'||tokens[index-1]?.value==='?.')
|
|
919
|
+
&&new Set(['globalThis','window','self']).has(tokens[index-2]?.value)
|
|
920
|
+
&&!identifierIsProperty(tokens,index-2))return index-2;
|
|
921
|
+
return -1;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
function localResourceBase(tokens){
|
|
925
|
+
if(!tokens)return false;
|
|
926
|
+
if(tokens.some(function nonExpressionToken(token){return !['identifier','punctuator'].includes(token.type);}))return false;
|
|
927
|
+
const base=tokens.map(function baseToken(token){return token.value;}).join('');
|
|
928
|
+
return [
|
|
929
|
+
'import.meta.url','document.baseURI','location.href','window.location.href',
|
|
930
|
+
'globalThis.location.href','self.location.href','window.document.baseURI',
|
|
931
|
+
'globalThis.document.baseURI'
|
|
932
|
+
].includes(base);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
function literalResourceFetch(argumentsList){
|
|
936
|
+
if(argumentsList.length===1)return true;
|
|
937
|
+
const options=argumentsList[1];
|
|
938
|
+
if(options?.[0]?.value!=='{'||options.at(-1)?.value!=='}')return false;
|
|
939
|
+
for(let index=1;index<options.length-1;index+=1){
|
|
940
|
+
const token=options[index];
|
|
941
|
+
if(token.value==='...'||(token.value==='.'&&options[index+1]?.value==='.'))return false;
|
|
942
|
+
if(token.value==='body')return false;
|
|
943
|
+
if(options[index+1]?.value!==':')continue;
|
|
944
|
+
if(token.value==='method'&&(options[index+2]?.type!=='string'
|
|
945
|
+
||!['GET','HEAD'].includes(options[index+2].value.toUpperCase())))return false;
|
|
946
|
+
}
|
|
947
|
+
return true;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
function reportAssetReference(onReference,url,kind,baseKind){
|
|
951
|
+
if(typeof onReference==='function')onReference({url,kind,baseHref:null,...(baseKind?{baseKind}:{})});
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
function javascriptReferenceEdits(source,version,onReference){
|
|
955
|
+
const tokens=tokenize(source);
|
|
956
|
+
const selected=new Map();
|
|
957
|
+
const imports=moduleImportsFromTokens(tokens,'asset source').imports;
|
|
958
|
+
const byOffset=new Map(tokens.map(function tokenByOffset(token){
|
|
959
|
+
return [token.start,token];
|
|
960
|
+
}));
|
|
961
|
+
for(const entry of imports){
|
|
962
|
+
reportAssetReference(onReference,entry.specifier,'import');
|
|
963
|
+
if(/^(?:\.{1,2}\/|\/)/u.test(entry.specifier)){
|
|
964
|
+
selected.set(entry.offset,byOffset.get(entry.offset));
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
for(let index=0;index<tokens.length;index+=1){
|
|
968
|
+
const token=tokens[index];
|
|
969
|
+
if(token.type!=='identifier'||tokens[index+1]?.value!=='(')continue;
|
|
970
|
+
if(!['URL','Worker','SharedWorker','importScripts','fetch'].includes(token.value))continue;
|
|
971
|
+
const callee=globalResourceCallee(tokens,index);
|
|
972
|
+
if(callee<0)continue;
|
|
973
|
+
const constructor=tokens[callee-1]?.value==='new';
|
|
974
|
+
if(['URL','Worker','SharedWorker'].includes(token.value)&&!constructor)continue;
|
|
975
|
+
const argumentsList=callArgumentTokens(tokens,index+1);
|
|
976
|
+
if(token.value==='fetch'&&!literalResourceFetch(argumentsList))continue;
|
|
977
|
+
if(token.value==='URL'&&!localResourceBase(argumentsList[1]))continue;
|
|
978
|
+
const selectedArguments=token.value==='importScripts'?argumentsList:argumentsList.slice(0,1);
|
|
979
|
+
for(const argument of selectedArguments){
|
|
980
|
+
for(const literal of literalExpressionResults(argument)){
|
|
981
|
+
if((token.value==='fetch'||token.value==='URL')
|
|
982
|
+
&&!RESOURCE_EXTENSION.test(literal.value))continue;
|
|
983
|
+
if((token.value==='fetch'||token.value==='URL')
|
|
984
|
+
&&/\.html?(?:[?#]|$)/iu.test(literal.value))continue;
|
|
985
|
+
const kind=token.value==='fetch'?'fetch'
|
|
986
|
+
:token.value==='URL'&&!/\.(?:js|mjs)(?:[?#]|$)/iu.test(literal.value)?'asset':'script';
|
|
987
|
+
const documentBase=['Worker','SharedWorker','fetch'].includes(token.value)
|
|
988
|
+
||(token.value==='URL'&&argumentsList[1]?.[0]?.value!=='import');
|
|
989
|
+
reportAssetReference(onReference,literal.value,kind,documentBase?'document':undefined);
|
|
990
|
+
selected.set(literal.start,literal);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
return [...selected.values()].map(function versionJavaScriptReference(token){
|
|
995
|
+
return stringReferenceEdit(source,token,version);
|
|
996
|
+
}).filter(Boolean);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
function cssStringEnd(source,start){
|
|
1000
|
+
const quote=source[start];
|
|
1001
|
+
let cursor=start+1;
|
|
1002
|
+
while(cursor<source.length){
|
|
1003
|
+
if(source[cursor]==='\\'){cursor+=2;continue;}
|
|
1004
|
+
if(source[cursor]===quote)return cursor+1;
|
|
1005
|
+
cursor+=1;
|
|
1006
|
+
}
|
|
1007
|
+
return source.length;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
function cssReferenceEdits(source,version,onReference,versionReference=versionAssetUrl){
|
|
1011
|
+
const edits=[];
|
|
1012
|
+
let cursor=0;
|
|
1013
|
+
let importUrlStart=-1;
|
|
1014
|
+
function skipSpaceAndComments(start){
|
|
1015
|
+
let position=start;
|
|
1016
|
+
while(position<source.length){
|
|
1017
|
+
if(/\s/u.test(source[position])){position+=1;continue;}
|
|
1018
|
+
if(source.startsWith('/*',position)){
|
|
1019
|
+
const close=source.indexOf('*/',position+2);
|
|
1020
|
+
position=close<0?source.length:close+2;
|
|
1021
|
+
continue;
|
|
1022
|
+
}
|
|
1023
|
+
break;
|
|
1024
|
+
}
|
|
1025
|
+
return position;
|
|
1026
|
+
}
|
|
1027
|
+
function addReference(start,end,kind='asset'){
|
|
1028
|
+
const original=source.slice(start,end);
|
|
1029
|
+
if(original.includes('\\'))return;
|
|
1030
|
+
reportAssetReference(onReference,original,kind);
|
|
1031
|
+
const value=versionReference(original,version);
|
|
1032
|
+
if(value!==original)edits.push({start,end,value});
|
|
1033
|
+
}
|
|
1034
|
+
while(cursor<source.length){
|
|
1035
|
+
if(source.startsWith('/*',cursor)){
|
|
1036
|
+
const end=source.indexOf('*/',cursor+2);
|
|
1037
|
+
cursor=end<0?source.length:end+2;
|
|
1038
|
+
continue;
|
|
1039
|
+
}
|
|
1040
|
+
if(source[cursor]==='"'||source[cursor]==="'"){
|
|
1041
|
+
cursor=cssStringEnd(source,cursor);
|
|
1042
|
+
continue;
|
|
1043
|
+
}
|
|
1044
|
+
const rest=source.slice(cursor);
|
|
1045
|
+
if(/^@import(?![\w-])/iu.test(rest)){
|
|
1046
|
+
const start=skipSpaceAndComments(cursor+7);
|
|
1047
|
+
importUrlStart=start;
|
|
1048
|
+
if(source[start]==='"'||source[start]==="'"){
|
|
1049
|
+
const end=cssStringEnd(source,start);
|
|
1050
|
+
addReference(start+1,end-1,'style');
|
|
1051
|
+
cursor=end;
|
|
1052
|
+
continue;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
if(!/[\w-]/u.test(source[cursor-1]??'')&&/^url\s*\(/iu.test(rest)){
|
|
1056
|
+
const kind=cursor===importUrlStart?'style':'asset';
|
|
1057
|
+
const open=source.indexOf('(',cursor);
|
|
1058
|
+
const start=skipSpaceAndComments(open+1);
|
|
1059
|
+
if(source[start]==='"'||source[start]==="'"){
|
|
1060
|
+
const end=cssStringEnd(source,start);
|
|
1061
|
+
addReference(start+1,end-1,kind);
|
|
1062
|
+
cursor=end;
|
|
1063
|
+
}else{
|
|
1064
|
+
let end=start;
|
|
1065
|
+
while(end<source.length&&source[end]!==')'){
|
|
1066
|
+
end+=source[end]==='\\'?2:1;
|
|
1067
|
+
}
|
|
1068
|
+
let valueEnd=Math.min(end,source.length);
|
|
1069
|
+
while(valueEnd>start&&/\s/u.test(source[valueEnd-1]))valueEnd-=1;
|
|
1070
|
+
addReference(start,valueEnd,kind);
|
|
1071
|
+
cursor=Math.min(end+1,source.length);
|
|
1072
|
+
}
|
|
1073
|
+
continue;
|
|
1074
|
+
}
|
|
1075
|
+
cursor+=1;
|
|
1076
|
+
}
|
|
1077
|
+
return edits;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
function importMapReferenceEdits(source,version,onReference){
|
|
1081
|
+
const tokens=tokenize(source);
|
|
1082
|
+
const edits=[];
|
|
1083
|
+
function objectProperties(start){
|
|
1084
|
+
if(tokens[start]?.type!=='punctuator'||tokens[start].value!=='{')return [];
|
|
1085
|
+
const properties=[];
|
|
1086
|
+
let cursor=start+1;
|
|
1087
|
+
while(cursor<tokens.length&&!(tokens[cursor].type==='punctuator'&&tokens[cursor].value==='}')){
|
|
1088
|
+
const key=tokens[cursor];
|
|
1089
|
+
if(key.type!=='string'||tokens[cursor+1]?.value!==':')return [];
|
|
1090
|
+
const valueIndex=cursor+2;
|
|
1091
|
+
const value=tokens[valueIndex];
|
|
1092
|
+
if(!value)return [];
|
|
1093
|
+
let end=valueIndex;
|
|
1094
|
+
if(value.type==='punctuator'&&(value.value==='{'||value.value==='[')){
|
|
1095
|
+
end=matchingToken(tokens,valueIndex,value.value,value.value==='{'?'}':']');
|
|
1096
|
+
if(end<0)return [];
|
|
1097
|
+
}
|
|
1098
|
+
properties.push({key:key.value,keyToken:key,valueIndex,value,end:tokens[end].end});
|
|
1099
|
+
cursor=end+1;
|
|
1100
|
+
if(tokens[cursor]?.value===',')cursor+=1;
|
|
1101
|
+
else if(tokens[cursor]?.value!=='}')return [];
|
|
1102
|
+
}
|
|
1103
|
+
return properties;
|
|
1104
|
+
}
|
|
1105
|
+
function addAlias(property,keys,value,aliases,alias=versionImportMapSpecifier(property.key,version)){
|
|
1106
|
+
if(alias===property.key||keys.has(alias))return;
|
|
1107
|
+
const keyEdit=stringReferenceEdit(source,property.keyToken,version,importMapUrlVersionEdits(property.key,version));
|
|
1108
|
+
if(!keyEdit)return;
|
|
1109
|
+
keys.add(alias);
|
|
1110
|
+
aliases.push(`${keyEdit.value}: ${value}`);
|
|
1111
|
+
}
|
|
1112
|
+
function prependAliases(start,aliases,selectedEdits){
|
|
1113
|
+
if(aliases.length===0)return;
|
|
1114
|
+
// Authored keys retain priority even when different spellings normalize to one URL.
|
|
1115
|
+
const offset=tokens[start].end;
|
|
1116
|
+
selectedEdits.push({start:offset,end:offset,value:`${aliases.join(', ')}, `});
|
|
1117
|
+
}
|
|
1118
|
+
function addImports(start){
|
|
1119
|
+
const selectedEdits=[];
|
|
1120
|
+
const aliases=[];
|
|
1121
|
+
const properties=objectProperties(start);
|
|
1122
|
+
const keys=new Set(properties.map(function importKey(property){return property.key;}));
|
|
1123
|
+
for(const property of properties){
|
|
1124
|
+
if(property.value.value==='null'&&property.value.type==='identifier'){
|
|
1125
|
+
addAlias(property,keys,'null',aliases);
|
|
1126
|
+
continue;
|
|
1127
|
+
}
|
|
1128
|
+
if(property.value.type!=='string')continue;
|
|
1129
|
+
if(property.key.endsWith('/'))continue;
|
|
1130
|
+
reportAssetReference(onReference,property.value.value,'import');
|
|
1131
|
+
const edit=property.value.value.split(/[?#]/u)[0].endsWith('/')
|
|
1132
|
+
?null:stringReferenceEdit(source,property.value,version);
|
|
1133
|
+
if(edit)selectedEdits.push(edit);
|
|
1134
|
+
addAlias(property,keys,edit?.value??source.slice(property.value.start,property.value.end),aliases);
|
|
1135
|
+
}
|
|
1136
|
+
prependAliases(start,aliases,selectedEdits);
|
|
1137
|
+
return selectedEdits;
|
|
1138
|
+
}
|
|
1139
|
+
for(const property of objectProperties(0)){
|
|
1140
|
+
if(property.key==='imports')edits.push(...addImports(property.valueIndex));
|
|
1141
|
+
if(property.key==='scopes'){
|
|
1142
|
+
const scopes=objectProperties(property.valueIndex);
|
|
1143
|
+
const aliases=[];
|
|
1144
|
+
const keys=new Set(scopes.map(function scopeKey(scope){return scope.key;}));
|
|
1145
|
+
for(const scope of scopes){
|
|
1146
|
+
const scopeEdits=addImports(scope.valueIndex);
|
|
1147
|
+
edits.push(...scopeEdits);
|
|
1148
|
+
const value=applyReferenceEdits(source.slice(scope.value.start,scope.end),scopeEdits.map(function scopeRelativeEdit(edit){
|
|
1149
|
+
return {...edit,start:edit.start-scope.value.start,end:edit.end-scope.value.start};
|
|
1150
|
+
}));
|
|
1151
|
+
if(!scope.key.endsWith('/'))addAlias(scope,keys,value,aliases,versionImportMapUrl(scope.key,version));
|
|
1152
|
+
}
|
|
1153
|
+
prependAliases(property.valueIndex,aliases,edits);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
return edits;
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
export function rewriteAssetReferences(source,{filePath,version=SDK_VERSION,onReference}={}){
|
|
1160
|
+
if(typeof source!=='string')throw new TypeError('Asset reference source must be a string.');
|
|
1161
|
+
const extension=path.extname(String(filePath??'')).toLowerCase();
|
|
1162
|
+
if(extension==='.js'||extension==='.mjs'){
|
|
1163
|
+
return applyReferenceEdits(source,javascriptReferenceEdits(source,version,onReference));
|
|
1164
|
+
}
|
|
1165
|
+
if(extension==='.css')return applyReferenceEdits(source,cssReferenceEdits(source,version,onReference));
|
|
1166
|
+
if(extension==='.html'||extension==='.htm'){
|
|
1167
|
+
return applyReferenceEdits(source,htmlReferenceEdits(source,version,onReference));
|
|
1168
|
+
}
|
|
1169
|
+
return source;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
787
1172
|
function registerSpecifier(registry,specifier,target){
|
|
788
1173
|
registry.set(specifier,{specifier,target});
|
|
789
1174
|
}
|
|
790
1175
|
|
|
1176
|
+
function versionImportMapSpecifier(specifier,version){
|
|
1177
|
+
if(specifier.endsWith('/')||!/^(?:\.{1,2}\/|\/|[A-Za-z][A-Za-z0-9+.-]*:\/\/)/u.test(specifier))return specifier;
|
|
1178
|
+
return versionImportMapUrl(specifier,version);
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
function versionImportMapUrl(value,version){
|
|
1182
|
+
return applyReferenceEdits(value,importMapUrlVersionEdits(value,version));
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
function importMapUrlVersionEdits(value,version){
|
|
1186
|
+
// Absolute map keys can match a relative import resolved against the document.
|
|
1187
|
+
const authority=/^(?:[A-Za-z][A-Za-z0-9+.-]*:)?\/\/[^/?#]*/u.exec(value)?.[0];
|
|
1188
|
+
const offset=authority?.length??0;
|
|
1189
|
+
return assetUrlVersionEdits(value.slice(offset),version).map(function absoluteKeyEdit(edit){
|
|
1190
|
+
return {...edit,start:edit.start+offset,end:edit.end+offset};
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
|
|
791
1194
|
function validateInventory(files){
|
|
792
1195
|
if(!Array.isArray(files))throw new TypeError('buildImportMap files must be an array.');
|
|
793
1196
|
const exact=new Set();
|
|
@@ -798,7 +1201,7 @@ function validateInventory(files){
|
|
|
798
1201
|
return exact;
|
|
799
1202
|
}
|
|
800
1203
|
|
|
801
|
-
export async function buildImportMap({files,signal}={}){
|
|
1204
|
+
export async function buildImportMap({files,signal,version=SDK_VERSION}={}){
|
|
802
1205
|
throwIfAborted(signal);
|
|
803
1206
|
const inventory=validateInventory(files);
|
|
804
1207
|
const modules=[...inventory]
|
|
@@ -858,9 +1261,16 @@ export async function buildImportMap({files,signal}={}){
|
|
|
858
1261
|
'./arcane/sdk/dependencies/event-pubsub/index.js'
|
|
859
1262
|
);
|
|
860
1263
|
}
|
|
1264
|
+
for(const relative of [...inventory].sort(compareText)){
|
|
1265
|
+
if(JAVASCRIPT_EXTENSION.test(relative)){
|
|
1266
|
+
registerSpecifier(namedRegistry,`./arcane/${relative}`,`./arcane/${relative}`);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
861
1269
|
const imports={};
|
|
862
1270
|
for(const entry of [...namedRegistry.values()].sort((left,right)=>compareText(left.specifier,right.specifier))){
|
|
863
|
-
|
|
1271
|
+
const target=versionAssetUrl(entry.target,version);
|
|
1272
|
+
imports[entry.specifier]=target;
|
|
1273
|
+
imports[versionImportMapSpecifier(entry.specifier,version)]=target;
|
|
864
1274
|
}
|
|
865
1275
|
return {
|
|
866
1276
|
imports,
|
|
@@ -918,9 +1328,22 @@ async function physicalRuntime(workspaceRoot,signal){
|
|
|
918
1328
|
|
|
919
1329
|
async function managedImportMapBuild(resolvedWorkspace,signal){
|
|
920
1330
|
const runtime=await physicalRuntime(resolvedWorkspace,signal);
|
|
921
|
-
const
|
|
1331
|
+
const version=await readWorkspaceAssetVersion(resolvedWorkspace);
|
|
1332
|
+
const built=await buildImportMap({files:runtime.files,signal,version});
|
|
922
1333
|
const json=`${JSON.stringify({imports:built.imports},null,2).replaceAll('<','\\u003c')}\n`;
|
|
923
|
-
return {built,json};
|
|
1334
|
+
return {built,json,version};
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
export async function readWorkspaceAssetVersion(workspaceRoot){
|
|
1338
|
+
let source;
|
|
1339
|
+
try{source=await readFileFromDisk(path.join(workspaceRoot,'arcane.lock.json'),'utf8');}
|
|
1340
|
+
catch(error){
|
|
1341
|
+
if(error?.code==='ENOENT')return SDK_VERSION;
|
|
1342
|
+
throw error;
|
|
1343
|
+
}
|
|
1344
|
+
const document=JSON.parse(source);
|
|
1345
|
+
const version=document?.sdk?.version;
|
|
1346
|
+
return typeof version==='string'&&version?version:SDK_VERSION;
|
|
924
1347
|
}
|
|
925
1348
|
|
|
926
1349
|
function asciiLower(value){
|
|
@@ -946,7 +1369,9 @@ function htmlTagName(value){
|
|
|
946
1369
|
function parseTagAttributes(openTag){
|
|
947
1370
|
const attributes=new Map();
|
|
948
1371
|
const duplicates=new Set();
|
|
1372
|
+
const positions=new Map();
|
|
949
1373
|
Object.defineProperty(attributes,'duplicates',{value:duplicates});
|
|
1374
|
+
Object.defineProperty(attributes,'positions',{value:positions});
|
|
950
1375
|
const tagHead=openTag.match(/^<[A-Za-z][^\t\n\f\r />]*(?=[\t\n\f\r />])/u);
|
|
951
1376
|
if(!tagHead)fail('Application HTML contains a malformed structural start tag.');
|
|
952
1377
|
let index=tagHead[0].length;
|
|
@@ -963,25 +1388,34 @@ function parseTagAttributes(openTag){
|
|
|
963
1388
|
const name=asciiLower(openTag.slice(start,index));
|
|
964
1389
|
while(/[\t\n\f\r ]/u.test(openTag[index]??''))index+=1;
|
|
965
1390
|
let value='';
|
|
1391
|
+
let valueStart=index;
|
|
1392
|
+
let valueEnd=index;
|
|
1393
|
+
let quote='';
|
|
966
1394
|
if(openTag[index]==='='){
|
|
967
1395
|
index+=1;
|
|
968
1396
|
while(/[\t\n\f\r ]/u.test(openTag[index]??''))index+=1;
|
|
969
|
-
|
|
1397
|
+
quote=openTag[index];
|
|
970
1398
|
if(quote==='\''||quote==='"'){
|
|
971
1399
|
index+=1;
|
|
972
|
-
|
|
1400
|
+
valueStart=index;
|
|
973
1401
|
while(index<openTag.length&&openTag[index]!==quote)index+=1;
|
|
1402
|
+
valueEnd=index;
|
|
974
1403
|
value=openTag.slice(valueStart,index);
|
|
975
1404
|
if(openTag[index]===quote)index+=1;
|
|
976
1405
|
}else{
|
|
977
|
-
|
|
1406
|
+
quote='';
|
|
1407
|
+
valueStart=index;
|
|
978
1408
|
while(index<openTag.length&&!/[\t\n\f\r >]/u.test(openTag[index]))index+=1;
|
|
1409
|
+
valueEnd=index;
|
|
979
1410
|
value=openTag.slice(valueStart,index);
|
|
980
1411
|
}
|
|
981
1412
|
}
|
|
982
1413
|
if(name){
|
|
983
1414
|
if(attributes.has(name))duplicates.add(name);
|
|
984
|
-
else
|
|
1415
|
+
else{
|
|
1416
|
+
attributes.set(name,value);
|
|
1417
|
+
positions.set(name,{start:valueStart,end:valueEnd,quote});
|
|
1418
|
+
}
|
|
985
1419
|
}
|
|
986
1420
|
}
|
|
987
1421
|
return attributes;
|
|
@@ -1004,7 +1438,9 @@ function decodeStructuralAttribute(value,label){
|
|
|
1004
1438
|
return String.fromCodePoint(point);
|
|
1005
1439
|
}
|
|
1006
1440
|
);
|
|
1007
|
-
if(
|
|
1441
|
+
if(/&(?:#[^;\s&]*|[A-Za-z][A-Za-z0-9]*);/u.test(source.replace(
|
|
1442
|
+
/&(?:#[0-9]+|#x[a-f0-9]+|amp|apos|gt|lt|quot);/giu,''
|
|
1443
|
+
))){
|
|
1008
1444
|
fail(
|
|
1009
1445
|
`Application HTML ${label} contains an unsupported or ambiguous character reference.`
|
|
1010
1446
|
);
|
|
@@ -1087,13 +1523,13 @@ function rawElementEnd(html,tag,openEnd){
|
|
|
1087
1523
|
const closePattern=new RegExp(`<\\/${tag}(?=[\\t\\n\\f\\r />]|$)`,'gi');
|
|
1088
1524
|
closePattern.lastIndex=openEnd;
|
|
1089
1525
|
const close=closePattern.exec(html);
|
|
1090
|
-
if(!close)return {end:html.length,closed:false};
|
|
1526
|
+
if(!close)return {end:html.length,contentEnd:html.length,closed:false};
|
|
1091
1527
|
const end=htmlTagEnd(html,close.index+close[0].length);
|
|
1092
1528
|
const closeTag=html.slice(close.index,end);
|
|
1093
1529
|
if(!new RegExp(`^<\\/${tag}[\\t\\n\\f\\r ]*>$`,'i').test(closeTag)){
|
|
1094
1530
|
fail(`Application HTML contains a malformed </${tag}> end tag.`);
|
|
1095
1531
|
}
|
|
1096
|
-
return {end,closed:true};
|
|
1532
|
+
return {end,contentEnd:close.index,closed:true};
|
|
1097
1533
|
}
|
|
1098
1534
|
|
|
1099
1535
|
function commentEnd(html,start){
|
|
@@ -1179,6 +1615,8 @@ function scanHtmlStructure(html){
|
|
|
1179
1615
|
const links=[];
|
|
1180
1616
|
const bases=[];
|
|
1181
1617
|
const metas=[];
|
|
1618
|
+
const elements=[];
|
|
1619
|
+
const styles=[];
|
|
1182
1620
|
let headClose=-1;
|
|
1183
1621
|
let bodyClose=-1;
|
|
1184
1622
|
let cursor=0;
|
|
@@ -1225,6 +1663,7 @@ function scanHtmlStructure(html){
|
|
|
1225
1663
|
cursor=openEnd;
|
|
1226
1664
|
continue;
|
|
1227
1665
|
}
|
|
1666
|
+
if(tag!=='template')elements.push({tag,start,end:openEnd,open});
|
|
1228
1667
|
if(tag==='link'){
|
|
1229
1668
|
links.push({start,end:openEnd,open});
|
|
1230
1669
|
cursor=openEnd;
|
|
@@ -1256,13 +1695,158 @@ function scanHtmlStructure(html){
|
|
|
1256
1695
|
if(tag==='script')scripts.push({
|
|
1257
1696
|
start,
|
|
1258
1697
|
openEnd,
|
|
1698
|
+
contentEnd:raw.contentEnd,
|
|
1259
1699
|
end:raw.end,
|
|
1260
1700
|
open,
|
|
1261
1701
|
closed:raw.closed
|
|
1262
1702
|
});
|
|
1703
|
+
if(tag==='style')styles.push({start:openEnd,end:raw.contentEnd});
|
|
1263
1704
|
cursor=raw.end;
|
|
1264
1705
|
}
|
|
1265
|
-
return {scripts,links,bases,metas,headClose,bodyClose};
|
|
1706
|
+
return {scripts,links,bases,metas,elements,styles,headClose,bodyClose};
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
function htmlAttributeView(value){
|
|
1710
|
+
let decoded='';
|
|
1711
|
+
const positions=[];
|
|
1712
|
+
for(let cursor=0;cursor<value.length;){
|
|
1713
|
+
const entity=value.slice(cursor).match(/^&(?:#([0-9]+)|#x([a-f0-9]+)|(amp|apos|gt|lt|quot));/iu);
|
|
1714
|
+
if(entity){
|
|
1715
|
+
const point=entity[1]||entity[2]
|
|
1716
|
+
?Number.parseInt(entity[1]??entity[2],entity[1]?10:16)
|
|
1717
|
+
:null;
|
|
1718
|
+
if(point!==null&&(!Number.isSafeInteger(point)||point<=0||point>0x10ffff))return null;
|
|
1719
|
+
const character=point===null
|
|
1720
|
+
?{amp:'&',apos:"'",gt:'>',lt:'<',quot:'"'}[asciiLower(entity[3])]
|
|
1721
|
+
:String.fromCodePoint(point);
|
|
1722
|
+
for(let index=0;index<character.length;index+=1)positions.push(cursor);
|
|
1723
|
+
decoded+=character;
|
|
1724
|
+
cursor+=entity[0].length;
|
|
1725
|
+
}else{
|
|
1726
|
+
if(/^&[A-Za-z][A-Za-z0-9]*;/u.test(value.slice(cursor)))return null;
|
|
1727
|
+
positions.push(cursor);
|
|
1728
|
+
decoded+=value[cursor++];
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
positions.push(value.length);
|
|
1732
|
+
return {decoded,positions};
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
function versionHtmlAttribute(value,version){
|
|
1736
|
+
// Map decoded URL positions back to authored HTML so existing query spelling survives.
|
|
1737
|
+
const view=htmlAttributeView(value);
|
|
1738
|
+
if(!view)return value;
|
|
1739
|
+
const {decoded,positions}=view;
|
|
1740
|
+
const edits=assetUrlVersionEdits(decoded,version).map(function authoredAttributeEdit(edit){
|
|
1741
|
+
return {
|
|
1742
|
+
start:positions[edit.start],
|
|
1743
|
+
end:positions[edit.end],
|
|
1744
|
+
value:edit.value.replaceAll('&','&')
|
|
1745
|
+
};
|
|
1746
|
+
});
|
|
1747
|
+
return applyReferenceEdits(value,edits);
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
function htmlStyleReferenceEdits(source,version,onReference){
|
|
1751
|
+
const view=htmlAttributeView(source);
|
|
1752
|
+
if(!view)return [];
|
|
1753
|
+
const edits=cssReferenceEdits(view.decoded,version,onReference);
|
|
1754
|
+
return edits.map(function authoredStyleReference(edit){
|
|
1755
|
+
const start=view.positions[edit.start];
|
|
1756
|
+
const end=view.positions[edit.end];
|
|
1757
|
+
return {start,end,value:versionHtmlAttribute(source.slice(start,end),version)};
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
function srcsetReferenceEdits(source,version,onReference){
|
|
1762
|
+
const edits=[];
|
|
1763
|
+
let cursor=0;
|
|
1764
|
+
while(cursor<source.length){
|
|
1765
|
+
while(/[\t\n\f\r ,]/u.test(source[cursor]??''))cursor+=1;
|
|
1766
|
+
const start=cursor;
|
|
1767
|
+
while(cursor<source.length&&!/[\t\n\f\r ]/u.test(source[cursor]))cursor+=1;
|
|
1768
|
+
let end=cursor;
|
|
1769
|
+
while(end>start&&source[end-1]===',')end-=1;
|
|
1770
|
+
const original=source.slice(start,end);
|
|
1771
|
+
const view=htmlAttributeView(original);
|
|
1772
|
+
if(view)reportAssetReference(onReference,view.decoded,'asset');
|
|
1773
|
+
const value=versionHtmlAttribute(original,version);
|
|
1774
|
+
if(value!==original)edits.push({start,end,value});
|
|
1775
|
+
if(end<cursor)continue;
|
|
1776
|
+
while(cursor<source.length&&source[cursor]!==',')cursor+=1;
|
|
1777
|
+
}
|
|
1778
|
+
return edits;
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
function htmlReferenceEdits(source,version,onReference){
|
|
1782
|
+
const structure=scanHtmlStructure(source);
|
|
1783
|
+
const edits=[];
|
|
1784
|
+
const sourceTags=new Set(['script','html-import','img','audio','video','source','track','iframe','embed']);
|
|
1785
|
+
const linkResources=new Set(['stylesheet','modulepreload','preload','icon','manifest']);
|
|
1786
|
+
const base=structure.bases[0];
|
|
1787
|
+
const baseHref=base?structuralAttribute(parseTagAttributes(base.open),'href','base'):null;
|
|
1788
|
+
if(baseHref&&(/^[A-Za-z][A-Za-z0-9+.-]*:/u.test(baseHref)||baseHref.startsWith('//')))version=null;
|
|
1789
|
+
function reportHtmlReference(reference){
|
|
1790
|
+
if(typeof onReference==='function')onReference({...reference,baseHref});
|
|
1791
|
+
}
|
|
1792
|
+
function addNestedEdits(offset,nested){
|
|
1793
|
+
for(const edit of nested)edits.push({...edit,start:offset+edit.start,end:offset+edit.end});
|
|
1794
|
+
}
|
|
1795
|
+
for(const element of structure.elements){
|
|
1796
|
+
const attributes=parseTagAttributes(element.open);
|
|
1797
|
+
const selected=[];
|
|
1798
|
+
const activeScript=element.tag!=='script'
|
|
1799
|
+
||['','module','text/javascript','application/javascript'].includes(scriptType(attributes));
|
|
1800
|
+
if(sourceTags.has(element.tag)&&element.tag!=='html-import'&&activeScript)selected.push('src');
|
|
1801
|
+
if(element.tag==='html-import')selected.push('href');
|
|
1802
|
+
if(element.tag==='video')selected.push('poster');
|
|
1803
|
+
if(element.tag==='object')selected.push('data');
|
|
1804
|
+
if(element.tag==='input'&&canonicalHtmlToken(attributes.get('type')??'')==='image')selected.push('src');
|
|
1805
|
+
const relationships=canonicalHtmlToken(attributes.get('rel')??'').split(/[\t\n\f\r ]+/u);
|
|
1806
|
+
if(element.tag==='link'){
|
|
1807
|
+
if(relationships.some(function loadsResource(relationship){return linkResources.has(relationship);})){selected.push('href');}
|
|
1808
|
+
}
|
|
1809
|
+
for(const name of selected){
|
|
1810
|
+
const original=attributes.get(name);
|
|
1811
|
+
if(!original)continue;
|
|
1812
|
+
const destination=canonicalHtmlToken(attributes.get('as')??'');
|
|
1813
|
+
const kind=element.tag==='script'?'script'
|
|
1814
|
+
:element.tag==='html-import'?'component'
|
|
1815
|
+
:element.tag==='iframe'?'document'
|
|
1816
|
+
:element.tag==='link'&&relationships.includes('stylesheet')?'style'
|
|
1817
|
+
:element.tag==='link'&&relationships.includes('modulepreload')?'script'
|
|
1818
|
+
:element.tag==='link'&&relationships.includes('preload')
|
|
1819
|
+
&&['script','worker','style'].includes(destination)?destination==='style'?'style':'script':'asset';
|
|
1820
|
+
const view=htmlAttributeView(original);
|
|
1821
|
+
if(view)reportAssetReference(reportHtmlReference,view.decoded,kind);
|
|
1822
|
+
const value=versionHtmlAttribute(original,version);
|
|
1823
|
+
if(value===original)continue;
|
|
1824
|
+
const position=attributes.positions.get(name);
|
|
1825
|
+
edits.push({start:element.start+position.start,end:element.start+position.end,value});
|
|
1826
|
+
}
|
|
1827
|
+
if((element.tag==='img'||element.tag==='source')&&attributes.has('srcset')){
|
|
1828
|
+
addNestedEdits(element.start+attributes.positions.get('srcset').start,
|
|
1829
|
+
srcsetReferenceEdits(attributes.get('srcset'),version,reportHtmlReference));
|
|
1830
|
+
}
|
|
1831
|
+
if(attributes.has('style')){
|
|
1832
|
+
addNestedEdits(element.start+attributes.positions.get('style').start,
|
|
1833
|
+
htmlStyleReferenceEdits(attributes.get('style'),version,reportHtmlReference));
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
for(const script of structure.scripts){
|
|
1837
|
+
const attributes=parseTagAttributes(script.open);
|
|
1838
|
+
if(attributes.has('src'))continue;
|
|
1839
|
+
const type=scriptType(attributes);
|
|
1840
|
+
const body=source.slice(script.openEnd,script.contentEnd);
|
|
1841
|
+
if(type==='importmap')addNestedEdits(script.openEnd,importMapReferenceEdits(body,version,reportHtmlReference));
|
|
1842
|
+
else if(['','module','text/javascript','application/javascript'].includes(type)){
|
|
1843
|
+
addNestedEdits(script.openEnd,javascriptReferenceEdits(body,version,reportHtmlReference));
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
for(const style of structure.styles){
|
|
1847
|
+
addNestedEdits(style.start,cssReferenceEdits(source.slice(style.start,style.end),version,reportHtmlReference));
|
|
1848
|
+
}
|
|
1849
|
+
return edits;
|
|
1266
1850
|
}
|
|
1267
1851
|
|
|
1268
1852
|
function removeManagedBlocks(html,blocks){
|
|
@@ -1579,7 +2163,7 @@ export async function createApplicationTestImportMapContext({
|
|
|
1579
2163
|
fail(`Application test import-map entry is invalid: ${String(specifier)}.`);
|
|
1580
2164
|
}
|
|
1581
2165
|
const relative=safeRelativePath(
|
|
1582
|
-
target.slice(2),
|
|
2166
|
+
decodeURIComponent(target.slice(2).split(/[?#]/u)[0]),
|
|
1583
2167
|
`application test import-map target for ${specifier}`
|
|
1584
2168
|
);
|
|
1585
2169
|
if(boundary==='source'&&/^(?:dist|test)\//u.test(relative)){
|
|
@@ -1699,10 +2283,13 @@ async function generateImportMapUnlocked({
|
|
|
1699
2283
|
renderManagedHtml(html,'{"imports":{}}\n',baseHref);
|
|
1700
2284
|
documentStates.push({filePath:documentPath,html,label,baseHref});
|
|
1701
2285
|
}
|
|
1702
|
-
const {built,json}=await managedImportMapBuild(resolvedWorkspace,signal);
|
|
2286
|
+
const {built,json,version}=await managedImportMapBuild(resolvedWorkspace,signal);
|
|
1703
2287
|
const renderedDocuments=documentStates.map(item=>({
|
|
1704
2288
|
...item,
|
|
1705
|
-
content:renderManagedHtml(item.html,json,item.baseHref)
|
|
2289
|
+
content:rewriteAssetReferences(renderManagedHtml(item.html,json,item.baseHref),{
|
|
2290
|
+
filePath:item.filePath,
|
|
2291
|
+
version
|
|
2292
|
+
})
|
|
1706
2293
|
}));
|
|
1707
2294
|
|
|
1708
2295
|
throwIfAborted(signal);
|