arcane-os 0.53.0 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/NOTICE +4 -1
- package/README.md +1 -1
- package/bin/arcane-test.mjs +2 -1
- package/browser-runtime/ai/browser-decisions.mjs +405 -0
- package/browser-runtime/ai/decision-runtime.mjs +281 -0
- package/browser-runtime/ai/decision-worker.mjs +67 -0
- package/browser-runtime/dependencies/event-pubsub/dependencies/strong-type/index.js +1151 -0
- package/browser-runtime/dependencies/event-pubsub/dependencies/strong-type/licence +21 -0
- package/browser-runtime/dependencies/event-pubsub/dependencies/strong-type/package.json +61 -0
- package/browser-runtime/dependencies/event-pubsub/index.js +2 -2
- package/browser-runtime/dependencies/event-pubsub/package.json +11 -4
- package/browser-runtime/dependencies/ws-share/WS.js +128 -0
- package/browser-runtime/dependencies/ws-share/licence.md +27 -0
- package/browser-runtime/dependencies/ws-share/package.json +64 -0
- package/browser-runtime/websocket-client.mjs +1 -0
- package/docs/event-manager.md +7 -4
- package/docs/reference/ai/browser-decisions.md +184 -0
- package/docs/reference/inventory/package-api.json +30 -2
- package/docs/reference/inventory/runtime-modules.json +17 -4
- package/docs/reference/protocols.md +76 -1
- package/docs/reference/runtime-modules.md +45 -2
- package/docs/reference/sdk-api.md +133 -9
- package/docs/reference/websocket-client.md +132 -0
- package/node_modules/event-pubsub/CHANGELOG.md +12 -1
- package/node_modules/event-pubsub/MIGRATION.md +8 -5
- package/node_modules/event-pubsub/README.md +75 -19
- package/node_modules/event-pubsub/SECURITY.md +3 -3
- package/node_modules/event-pubsub/index.js +2 -2
- package/node_modules/event-pubsub/package.json +11 -4
- package/package.json +8 -5
- package/runtime/arcane/modules/HTMLImport.js +81 -26
- package/runtime/arcane/modules/HTMLImportScript.js +3 -0
- package/src/import-map.mjs +416 -59
- package/src/index.mjs +1 -0
- package/src/packager/core.mjs +24 -6
- package/src/packager/native-modules.mjs +458 -0
- package/src/testing-loader.mjs +41 -20
package/src/import-map.mjs
CHANGED
|
@@ -41,11 +41,13 @@ const STATIC_RUNTIME_PACKAGE_IMPORTS=new Map([
|
|
|
41
41
|
]);
|
|
42
42
|
const SDK_BROWSER_SELF_IMPORTS=new Map([
|
|
43
43
|
['arcane-os/event-manager',SDK_BROWSER_ENTRY],
|
|
44
|
+
['arcane-os/websocket-client','sdk/websocket-client.mjs'],
|
|
44
45
|
['arcane-os/logging','sdk/logging.mjs'],
|
|
45
46
|
['arcane-os/browser-device','sdk/browser-device.mjs'],
|
|
46
47
|
['arcane-os/pwa','sdk/pwa.mjs'],
|
|
47
48
|
['arcane-os/speech-text','sdk/speech-text.mjs'],
|
|
48
49
|
['arcane-os/ai/browser-wasm',SDK_BROWSER_AI_ENTRY],
|
|
50
|
+
['arcane-os/ai/browser-decisions','sdk/ai/browser-decisions.mjs'],
|
|
49
51
|
['arcane-os/ai/tool-text-stream','sdk/ai/tool-text-stream.mjs'],
|
|
50
52
|
['arcane-os/ai/twin-cloud','sdk/ai/twin-cloud.mjs'],
|
|
51
53
|
['arcane-os/ai/browser-speech',SDK_BROWSER_SPEECH_ENTRY]
|
|
@@ -946,17 +948,234 @@ function literalExpressionResults(tokens){
|
|
|
946
948
|
return [];
|
|
947
949
|
}
|
|
948
950
|
|
|
949
|
-
function
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
951
|
+
function resourceBindingScopes(tokens){
|
|
952
|
+
const relevant=new Set([
|
|
953
|
+
'fetch','URL','Worker','SharedWorker','importScripts',
|
|
954
|
+
'globalThis','window','self','document','location'
|
|
955
|
+
]);
|
|
956
|
+
const bindings=new Map();
|
|
957
|
+
const closing=new Map();
|
|
958
|
+
const opening=new Map();
|
|
959
|
+
const delimiters=[];
|
|
960
|
+
for(let index=0;index<tokens.length;index+=1){
|
|
961
|
+
if(tokens[index].type!=='punctuator')continue;
|
|
962
|
+
const value=tokens[index].value;
|
|
963
|
+
if(['(','[','{'].includes(value))delimiters.push(index);
|
|
964
|
+
else if([')',']','}'].includes(value)){
|
|
965
|
+
const start=delimiters.pop();
|
|
966
|
+
if(start!==undefined){closing.set(start,index);opening.set(index,start);}
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
const root={start:0,end:tokens.length,kind:'module',parent:null};
|
|
971
|
+
const scopeAt=[];
|
|
972
|
+
let scope=root;
|
|
973
|
+
for(let index=0;index<tokens.length;index+=1){
|
|
974
|
+
scopeAt[index]=scope;
|
|
975
|
+
if(tokens[index].type!=='punctuator')continue;
|
|
976
|
+
if(tokens[index].value==='{'){
|
|
977
|
+
scope={
|
|
978
|
+
start:index,end:closing.get(index)??tokens.length,
|
|
979
|
+
kind:tokens[index].openingBraceKind,parent:scope
|
|
980
|
+
};
|
|
981
|
+
}else if(tokens[index].value==='}')scope=scope.parent??root;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
function bind(index,owner){
|
|
985
|
+
const token=tokens[index];
|
|
986
|
+
if(token?.type!=='identifier'||!relevant.has(token.value))return;
|
|
987
|
+
const entries=bindings.get(token.value)??[];
|
|
988
|
+
entries.push({
|
|
989
|
+
start:tokens[owner.start]?.start??0,
|
|
990
|
+
end:tokens[owner.end]?.end??tokens.at(-1)?.end??0
|
|
991
|
+
});
|
|
992
|
+
bindings.set(token.value,entries);
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
function patterns(start,end,owner){
|
|
996
|
+
const boundaries=[start-1,...topLevelCommas(tokens,start,end),end];
|
|
997
|
+
for(let index=0;index<boundaries.length-1;index+=1){
|
|
998
|
+
pattern(boundaries[index]+1,boundaries[index+1],owner);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
function pattern(start,end,owner){
|
|
1003
|
+
if(start>=end)return;
|
|
1004
|
+
if(tokens[start]?.value==='...')start+=1;
|
|
1005
|
+
const token=tokens[start];
|
|
1006
|
+
if(token?.type==='identifier'){bind(start,owner);return;}
|
|
1007
|
+
const close=closing.get(start);
|
|
1008
|
+
if(close===undefined||close>=end)return;
|
|
1009
|
+
if(token.value==='['){patterns(start+1,close,owner);return;}
|
|
1010
|
+
if(token.value!=='{')return;
|
|
1011
|
+
const boundaries=[start,...topLevelCommas(tokens,start+1,close),close];
|
|
1012
|
+
for(let index=0;index<boundaries.length-1;index+=1){
|
|
1013
|
+
const entry=boundaries[index]+1;
|
|
1014
|
+
const finish=boundaries[index+1];
|
|
1015
|
+
const keyEnd=tokens[entry]?.value==='['?closing.get(entry):entry;
|
|
1016
|
+
const value=tokens[keyEnd+1]?.value===':'?keyEnd+2:entry;
|
|
1017
|
+
pattern(value,finish,owner);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
function expressionEnd(start,{declaration=false}={}){
|
|
1022
|
+
let index=start;
|
|
1023
|
+
while(index<tokens.length){
|
|
1024
|
+
const token=tokens[index];
|
|
1025
|
+
if(token.type==='punctuator'){
|
|
1026
|
+
if([';',')',']','}'].includes(token.value))break;
|
|
1027
|
+
if(!declaration&&token.value===',')break;
|
|
1028
|
+
if(closing.has(index)){index=closing.get(index)+1;continue;}
|
|
1029
|
+
}
|
|
1030
|
+
if(declaration&&token.type==='identifier'&&token.lineBreakBefore
|
|
1031
|
+
&&['const','let','var','export','return'].includes(token.value))break;
|
|
1032
|
+
index+=1;
|
|
1033
|
+
}
|
|
1034
|
+
return index;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
function namedDefinitionEnd(start) {
|
|
1038
|
+
let index = start + 1;
|
|
1039
|
+
while (index < tokens.length) {
|
|
1040
|
+
const token = tokens[index];
|
|
1041
|
+
if (token.type === 'punctuator' && token.value === '{') return closing.get(index);
|
|
1042
|
+
if (closing.has(index)) {
|
|
1043
|
+
index = closing.get(index) + 1;
|
|
1044
|
+
continue;
|
|
1045
|
+
}
|
|
1046
|
+
if (token.type === 'identifier' && ['function', 'class'].includes(token.value)
|
|
1047
|
+
&& !identifierIsProperty(tokens, index)) {
|
|
1048
|
+
const end = namedDefinitionEnd(index);
|
|
1049
|
+
if (end === undefined) return undefined;
|
|
1050
|
+
index = end + 1;
|
|
1051
|
+
continue;
|
|
1052
|
+
}
|
|
1053
|
+
index += 1;
|
|
1054
|
+
}
|
|
1055
|
+
return undefined;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
function namedDefinitionIsDeclaration(index) {
|
|
1059
|
+
const token = tokens[index];
|
|
1060
|
+
const async = token.value === 'function' && tokens[index - 1]?.value === 'async'
|
|
1061
|
+
&& !token.lineBreakBefore && !identifierIsProperty(tokens, index - 1);
|
|
1062
|
+
const start = async ? index - 1 : index;
|
|
1063
|
+
if (declarationPosition(tokens, start)) return true;
|
|
1064
|
+
const previous = tokens[start - 1];
|
|
1065
|
+
if (previous?.value === ':' && previous.enclosingBraceKind !== 'object') {
|
|
1066
|
+
if (declarationPosition(tokens, start - 2)) return true;
|
|
1067
|
+
let conditionals = 0;
|
|
1068
|
+
for (let cursor = start - 2; cursor >= scopeAt[index].start; cursor -= 1) {
|
|
1069
|
+
if (opening.has(cursor)) {
|
|
1070
|
+
cursor = opening.get(cursor);
|
|
1071
|
+
continue;
|
|
1072
|
+
}
|
|
1073
|
+
const candidate = tokens[cursor];
|
|
1074
|
+
const value = candidate.value;
|
|
1075
|
+
if (value === ':') conditionals += 1;
|
|
1076
|
+
else if (value === '?') {
|
|
1077
|
+
if (conditionals === 0) return false;
|
|
1078
|
+
conditionals -= 1;
|
|
1079
|
+
} else if (candidate.type === 'identifier' && ['case', 'default'].includes(value)
|
|
1080
|
+
&& !identifierIsProperty(tokens, cursor)) return conditionals === 0;
|
|
1081
|
+
else if ([';', '{', '}'].includes(value)) break;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
// An omitted semicolon must not turn a following declaration into an expression.
|
|
1085
|
+
if (!tokens[start].lineBreakBefore || !previous) return false;
|
|
1086
|
+
if (['string', 'number', 'regex', 'template'].includes(previous.type)) return true;
|
|
1087
|
+
if (previous.type === 'identifier') {
|
|
1088
|
+
if (identifierIsProperty(tokens, start - 1)) return true;
|
|
1089
|
+
if (['return', 'throw', 'yield'].includes(previous.value)) return true;
|
|
1090
|
+
if (previous.contextualRegexPrefix === true) return false;
|
|
1091
|
+
if (previous.value === 'await' && previous.slashGoalAfter !== 'division') return false;
|
|
1092
|
+
return !REGEX_PREFIX_KEYWORDS.has(previous.value);
|
|
1093
|
+
}
|
|
1094
|
+
return [')', ']', '++', '--'].includes(previous.value);
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
for(let index=0;index<tokens.length;index+=1){
|
|
1098
|
+
const token=tokens[index];
|
|
1099
|
+
if(token.type==='punctuator'&&token.value==='{'&&tokens[index-1]?.value===')'
|
|
1100
|
+
&&tokens[index-1]?.closesControl!==true){
|
|
1101
|
+
const start=opening.get(index-1);
|
|
1102
|
+
if(start!==undefined){
|
|
1103
|
+
patterns(start+1,index-1,{start,end:closing.get(index)??tokens.length});
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
if(token.type==='punctuator'&&token.value==='=>'){
|
|
1107
|
+
const previous=index-1;
|
|
1108
|
+
const parameterStart=tokens[previous]?.value===')'?opening.get(previous):previous;
|
|
1109
|
+
if(parameterStart!==undefined){
|
|
1110
|
+
const end=tokens[index+1]?.value==='{'?closing.get(index+1):expressionEnd(index+1);
|
|
1111
|
+
const owner={start:parameterStart,end:end??tokens.length};
|
|
1112
|
+
if(tokens[previous]?.value===')')patterns(parameterStart+1,previous,owner);
|
|
1113
|
+
else pattern(parameterStart,index,owner);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
if(token.type!=='identifier'||identifierIsProperty(tokens,index))continue;
|
|
1117
|
+
if(['const','let','var'].includes(token.value)){
|
|
1118
|
+
let owner=scopeAt[index];
|
|
1119
|
+
if(token.value==='var'){
|
|
1120
|
+
while(owner.parent&&owner.kind!=='function')owner=owner.parent;
|
|
1121
|
+
}
|
|
1122
|
+
// Loop bindings conservatively retain the enclosing lexical scope.
|
|
1123
|
+
patterns(index+1,expressionEnd(index+1,{declaration:true}),owner);
|
|
1124
|
+
}else if(token.value==='function'||token.value==='class'){
|
|
1125
|
+
const name = tokens[index + 1]?.value === '*' ? index + 2 : index + 1;
|
|
1126
|
+
if (tokens[name]?.type !== 'identifier' || !relevant.has(tokens[name].value)) continue;
|
|
1127
|
+
const end = namedDefinitionIsDeclaration(index) ? undefined : namedDefinitionEnd(index);
|
|
1128
|
+
// Expression names belong to their own parameters/heritage and body only.
|
|
1129
|
+
const owner = end === undefined ? scopeAt[index] : {start: index, end};
|
|
1130
|
+
bind(name, owner);
|
|
1131
|
+
}else if(token.value==='catch'&&tokens[index+1]?.value==='('){
|
|
1132
|
+
const close=closing.get(index+1);
|
|
1133
|
+
const body=close+1;
|
|
1134
|
+
if(close!==undefined&&tokens[body]?.value==='{'){
|
|
1135
|
+
patterns(index+2,close,{start:index+1,end:closing.get(body)??tokens.length});
|
|
1136
|
+
}
|
|
1137
|
+
}else if(token.value==='import'&&!['(','.'].includes(tokens[index+1]?.value)
|
|
1138
|
+
&&tokens[index+1]?.type!=='string'){
|
|
1139
|
+
let cursor=index+1;
|
|
1140
|
+
if(tokens[cursor]?.type==='identifier'){bind(cursor,root);cursor+=1;}
|
|
1141
|
+
if(tokens[cursor]?.value===',')cursor+=1;
|
|
1142
|
+
if(tokens[cursor]?.value==='*'&&tokens[cursor+1]?.value==='as')bind(cursor+2,root);
|
|
1143
|
+
else if(tokens[cursor]?.value==='{'){
|
|
1144
|
+
const close=closing.get(cursor)??cursor;
|
|
1145
|
+
const boundaries=[cursor,...topLevelCommas(tokens,cursor+1,close),close];
|
|
1146
|
+
for(let entry=0;entry<boundaries.length-1;entry+=1){
|
|
1147
|
+
const start=boundaries[entry]+1;
|
|
1148
|
+
bind(tokens[start+1]?.value==='as'?start+2:start,root);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
return bindings;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
function locallyBoundResource(token,bindings){
|
|
1157
|
+
const owners=bindings.get(token.value)??[];
|
|
1158
|
+
return owners.some(function containsReference(owner){
|
|
1159
|
+
return token.start>=owner.start&&token.start<=owner.end;
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
function globalResourceCallee(tokens,index,bindings){
|
|
1164
|
+
let root=index;
|
|
1165
|
+
if(identifierIsProperty(tokens,index)){
|
|
1166
|
+
if((tokens[index-1]?.value!=='.'&&tokens[index-1]?.value!=='?.')
|
|
1167
|
+
||!['globalThis','window','self'].includes(tokens[index-2]?.value)
|
|
1168
|
+
||identifierIsProperty(tokens,index-2))return -1;
|
|
1169
|
+
root=index-2;
|
|
1170
|
+
}
|
|
1171
|
+
if(locallyBoundResource(tokens[root],bindings))return -1;
|
|
1172
|
+
return root;
|
|
955
1173
|
}
|
|
956
1174
|
|
|
957
|
-
function localResourceBase(tokens){
|
|
1175
|
+
function localResourceBase(tokens,bindings){
|
|
958
1176
|
if(!tokens)return false;
|
|
959
1177
|
if(tokens.some(function nonExpressionToken(token){return !['identifier','punctuator'].includes(token.type);}))return false;
|
|
1178
|
+
if(tokens[0]?.value!=='import'&&tokens[0]&&locallyBoundResource(tokens[0],bindings))return false;
|
|
960
1179
|
const base=tokens.map(function baseToken(token){return token.value;}).join('');
|
|
961
1180
|
return [
|
|
962
1181
|
'import.meta.url','document.baseURI','location.href','window.location.href',
|
|
@@ -984,8 +1203,9 @@ function reportAssetReference(onReference,url,kind,baseKind){
|
|
|
984
1203
|
if(is.function(onReference))onReference({url,kind,baseHref:null,...(baseKind?{baseKind}:{})});
|
|
985
1204
|
}
|
|
986
1205
|
|
|
987
|
-
function javascriptReferenceEdits(source,version,onReference){
|
|
1206
|
+
function javascriptReferenceEdits(source,version,onReference,resolveReference){
|
|
988
1207
|
const tokens=tokenize(source);
|
|
1208
|
+
const resourceBindings=resourceBindingScopes(tokens);
|
|
989
1209
|
const selected=new Map();
|
|
990
1210
|
const imports=moduleImportsFromTokens(tokens,'asset source').imports;
|
|
991
1211
|
const byOffset=new Map(tokens.map(function tokenByOffset(token){
|
|
@@ -993,38 +1213,55 @@ function javascriptReferenceEdits(source,version,onReference){
|
|
|
993
1213
|
}));
|
|
994
1214
|
for(const entry of imports){
|
|
995
1215
|
reportAssetReference(onReference,entry.specifier,'import');
|
|
996
|
-
if(
|
|
997
|
-
selected.set(entry.offset,byOffset.get(entry.offset));
|
|
1216
|
+
if(resolveReference||/^(?:\.{1,2}\/|\/)/u.test(entry.specifier)){
|
|
1217
|
+
selected.set(entry.offset,{token:byOffset.get(entry.offset),kind:'import'});
|
|
998
1218
|
}
|
|
999
1219
|
}
|
|
1000
1220
|
for(let index=0;index<tokens.length;index+=1){
|
|
1001
1221
|
const token=tokens[index];
|
|
1222
|
+
if(resolveReference&&token.type==='identifier'&&token.value==='import'
|
|
1223
|
+
&&!identifierIsProperty(tokens,index)&&tokens[index+1]?.value==='.'
|
|
1224
|
+
&&tokens[index+2]?.value==='meta'&&tokens[index+3]?.value==='.'
|
|
1225
|
+
&&tokens[index+4]?.value==='resolve'&&tokens[index+5]?.value==='('
|
|
1226
|
+
&&tokens[index+6]?.type==='string'&&tokens[index+7]?.value===')'){
|
|
1227
|
+
const literal=tokens[index+6];
|
|
1228
|
+
selected.set(literal.start,{token:literal,kind:'import-resolve'});
|
|
1229
|
+
}
|
|
1002
1230
|
if(token.type!=='identifier'||tokens[index+1]?.value!=='(')continue;
|
|
1003
1231
|
if(!['URL','Worker','SharedWorker','importScripts','fetch'].includes(token.value))continue;
|
|
1004
|
-
const callee=globalResourceCallee(tokens,index);
|
|
1232
|
+
const callee=globalResourceCallee(tokens,index,resourceBindings);
|
|
1005
1233
|
if(callee<0)continue;
|
|
1006
1234
|
const constructor=tokens[callee-1]?.value==='new';
|
|
1007
1235
|
if(['URL','Worker','SharedWorker'].includes(token.value)&&!constructor)continue;
|
|
1008
1236
|
const argumentsList=callArgumentTokens(tokens,index+1);
|
|
1009
1237
|
if(token.value==='fetch'&&!literalResourceFetch(argumentsList))continue;
|
|
1010
|
-
if(token.value==='URL'&&!localResourceBase(argumentsList[1]))continue;
|
|
1238
|
+
if(token.value==='URL'&&!localResourceBase(argumentsList[1],resourceBindings))continue;
|
|
1011
1239
|
const selectedArguments=token.value==='importScripts'?argumentsList:argumentsList.slice(0,1);
|
|
1012
1240
|
for(const argument of selectedArguments){
|
|
1013
1241
|
for(const literal of literalExpressionResults(argument)){
|
|
1014
1242
|
if((token.value==='fetch'||token.value==='URL')
|
|
1015
1243
|
&&!RESOURCE_EXTENSION.test(literal.value))continue;
|
|
1016
1244
|
if((token.value==='fetch'||token.value==='URL')
|
|
1017
|
-
&&/\.html?(?:[?#]|$)/iu.test(literal.value))continue;
|
|
1245
|
+
&&!resolveReference&&/\.html?(?:[?#]|$)/iu.test(literal.value))continue;
|
|
1018
1246
|
const kind=token.value==='fetch'?'fetch'
|
|
1019
1247
|
:token.value==='URL'&&!/\.(?:js|mjs)(?:[?#]|$)/iu.test(literal.value)?'asset':'script';
|
|
1020
1248
|
const documentBase=['Worker','SharedWorker','fetch'].includes(token.value)
|
|
1021
1249
|
||(token.value==='URL'&&argumentsList[1]?.[0]?.value!=='import');
|
|
1022
1250
|
reportAssetReference(onReference,literal.value,kind,documentBase?'document':undefined);
|
|
1023
|
-
selected.set(literal.start,
|
|
1251
|
+
selected.set(literal.start,{
|
|
1252
|
+
token:literal,
|
|
1253
|
+
kind,
|
|
1254
|
+
baseKind:documentBase?'document':undefined
|
|
1255
|
+
});
|
|
1024
1256
|
}
|
|
1025
1257
|
}
|
|
1026
1258
|
}
|
|
1027
|
-
return [...selected.values()].map(function versionJavaScriptReference(token){
|
|
1259
|
+
return [...selected.values()].map(function versionJavaScriptReference({token,kind,baseKind}){
|
|
1260
|
+
if(resolveReference){
|
|
1261
|
+
const value=resolveReference({url:token.value,kind,baseKind});
|
|
1262
|
+
if(value===undefined||value===token.value)return null;
|
|
1263
|
+
return stringReferenceEdit(source,token,null,[{start:0,end:token.value.length,value}]);
|
|
1264
|
+
}
|
|
1028
1265
|
return stringReferenceEdit(source,token,version);
|
|
1029
1266
|
}).filter(Boolean);
|
|
1030
1267
|
}
|
|
@@ -1061,7 +1298,7 @@ function cssReferenceEdits(source,version,onReference,versionReference=versionAs
|
|
|
1061
1298
|
const original=source.slice(start,end);
|
|
1062
1299
|
if(original.includes('\\'))return;
|
|
1063
1300
|
reportAssetReference(onReference,original,kind);
|
|
1064
|
-
const value=versionReference(original,version);
|
|
1301
|
+
const value=versionReference(original,version,kind);
|
|
1065
1302
|
if(value!==original)edits.push({start,end,value});
|
|
1066
1303
|
}
|
|
1067
1304
|
while(cursor<source.length){
|
|
@@ -1233,6 +1470,19 @@ function registerSpecifier(registry,specifier,target){
|
|
|
1233
1470
|
registry.set(specifier,{specifier,target});
|
|
1234
1471
|
}
|
|
1235
1472
|
|
|
1473
|
+
function translateImportMapScopes(scopes, translateUrl) {
|
|
1474
|
+
if (scopes === undefined) return undefined;
|
|
1475
|
+
const translated = {};
|
|
1476
|
+
for (const [scope, entries] of Object.entries(scopes)) {
|
|
1477
|
+
const imports = {};
|
|
1478
|
+
for (const [specifier, target] of Object.entries(entries)) {
|
|
1479
|
+
imports[translateUrl(specifier)] = translateUrl(target);
|
|
1480
|
+
}
|
|
1481
|
+
translated[translateUrl(scope)] = imports;
|
|
1482
|
+
}
|
|
1483
|
+
return translated;
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1236
1486
|
function versionImportMapSpecifier(specifier,version){
|
|
1237
1487
|
if(specifier.endsWith('/')||!/^(?:\.{1,2}\/|\/|[A-Za-z][A-Za-z0-9+.-]*:\/\/)/u.test(specifier))return specifier;
|
|
1238
1488
|
return versionImportMapUrl(specifier,version);
|
|
@@ -1328,6 +1578,13 @@ export async function buildImportMap({files,signal,version=SDK_VERSION,encodePat
|
|
|
1328
1578
|
'./arcane/sdk/dependencies/event-pubsub/index.js'
|
|
1329
1579
|
);
|
|
1330
1580
|
}
|
|
1581
|
+
if (inventory.has('sdk/dependencies/ws-share/WS.js')) {
|
|
1582
|
+
registerSpecifier(
|
|
1583
|
+
namedRegistry,
|
|
1584
|
+
'ws-share',
|
|
1585
|
+
'./arcane/sdk/dependencies/ws-share/WS.js'
|
|
1586
|
+
);
|
|
1587
|
+
}
|
|
1331
1588
|
for(const relative of [...inventory].sort(compareText)){
|
|
1332
1589
|
if(JAVASCRIPT_EXTENSION.test(relative)){
|
|
1333
1590
|
const target=runtimeTarget(relative);
|
|
@@ -1343,10 +1600,22 @@ export async function buildImportMap({files,signal,version=SDK_VERSION,encodePat
|
|
|
1343
1600
|
imports[entry.specifier]=target;
|
|
1344
1601
|
imports[versionImportMapSpecifier(entry.specifier,version)]=target;
|
|
1345
1602
|
}
|
|
1346
|
-
|
|
1603
|
+
const result = {
|
|
1347
1604
|
imports,
|
|
1348
1605
|
excludedModules:[]
|
|
1349
1606
|
};
|
|
1607
|
+
if (inventory.has('sdk/dependencies/event-pubsub/index.js')
|
|
1608
|
+
&& inventory.has('sdk/dependencies/event-pubsub/dependencies/strong-type/index.js')) {
|
|
1609
|
+
result.scopes = {
|
|
1610
|
+
'./arcane/sdk/dependencies/event-pubsub/': {
|
|
1611
|
+
'strong-type': versionAssetUrl(
|
|
1612
|
+
'./arcane/sdk/dependencies/event-pubsub/dependencies/strong-type/index.js',
|
|
1613
|
+
version
|
|
1614
|
+
)
|
|
1615
|
+
}
|
|
1616
|
+
};
|
|
1617
|
+
}
|
|
1618
|
+
return result;
|
|
1350
1619
|
}
|
|
1351
1620
|
|
|
1352
1621
|
function pathInside(root,target){
|
|
@@ -1426,8 +1695,13 @@ async function managedImportMapBuild(resolvedWorkspace,resolvedApp,signal){
|
|
|
1426
1695
|
if(physicalCompatibilityUrl)imports[physicalCompatibilityUrl]=selected;
|
|
1427
1696
|
}
|
|
1428
1697
|
built.imports=imports;
|
|
1698
|
+
if (built.scopes !== undefined) {
|
|
1699
|
+
built.scopes = translateImportMapScopes(built.scopes, installedBrowserUrl);
|
|
1700
|
+
}
|
|
1429
1701
|
}
|
|
1430
|
-
const
|
|
1702
|
+
const document = {imports:built.imports};
|
|
1703
|
+
if (built.scopes !== undefined) document.scopes = built.scopes;
|
|
1704
|
+
const json=`${JSON.stringify(document,null,2).replaceAll('<','\\u003c')}\n`;
|
|
1431
1705
|
return {built,json,version};
|
|
1432
1706
|
}
|
|
1433
1707
|
|
|
@@ -1512,10 +1786,16 @@ function parseTagAttributes(openTag){
|
|
|
1512
1786
|
}
|
|
1513
1787
|
}
|
|
1514
1788
|
if(name){
|
|
1515
|
-
|
|
1789
|
+
const position={start:valueStart,end:valueEnd,quote,nameEnd,assigned};
|
|
1790
|
+
if(attributes.has(name)){
|
|
1791
|
+
duplicates.add(name);
|
|
1792
|
+
const original=positions.get(name);
|
|
1793
|
+
original.additional??=[];
|
|
1794
|
+
original.additional.push(position);
|
|
1795
|
+
}
|
|
1516
1796
|
else{
|
|
1517
1797
|
attributes.set(name,value);
|
|
1518
|
-
positions.set(name,
|
|
1798
|
+
positions.set(name,position);
|
|
1519
1799
|
}
|
|
1520
1800
|
}
|
|
1521
1801
|
}
|
|
@@ -1954,11 +2234,12 @@ function htmlStyleReferenceEdits(source,version,onReference){
|
|
|
1954
2234
|
});
|
|
1955
2235
|
}
|
|
1956
2236
|
|
|
1957
|
-
function srcsetReferenceEdits(source,version,onReference){
|
|
2237
|
+
function srcsetReferenceEdits(source,version,onReference,versionReference=versionHtmlAttribute){
|
|
1958
2238
|
const edits=[];
|
|
1959
2239
|
let cursor=0;
|
|
1960
2240
|
while(cursor<source.length){
|
|
1961
2241
|
while(/[\t\n\f\r ,]/u.test(source[cursor]??''))cursor+=1;
|
|
2242
|
+
if(cursor===source.length)break;
|
|
1962
2243
|
const start=cursor;
|
|
1963
2244
|
while(cursor<source.length&&!/[\t\n\f\r ]/u.test(source[cursor]))cursor+=1;
|
|
1964
2245
|
let end=cursor;
|
|
@@ -1966,7 +2247,7 @@ function srcsetReferenceEdits(source,version,onReference){
|
|
|
1966
2247
|
const original=source.slice(start,end);
|
|
1967
2248
|
const view=htmlAttributeView(original);
|
|
1968
2249
|
if(view)reportAssetReference(onReference,view.decoded,'asset');
|
|
1969
|
-
const value=
|
|
2250
|
+
const value=versionReference(original,version);
|
|
1970
2251
|
if(value!==original)edits.push({start,end,value});
|
|
1971
2252
|
if(end<cursor)continue;
|
|
1972
2253
|
while(cursor<source.length&&source[cursor]!==',')cursor+=1;
|
|
@@ -2150,6 +2431,52 @@ export function inspectImportMapHtml(html){
|
|
|
2150
2431
|
};
|
|
2151
2432
|
}
|
|
2152
2433
|
|
|
2434
|
+
// Packaging shares the same lexical and HTML owners as managed browser maps.
|
|
2435
|
+
// These internal helpers edit only executable/resource references, never prose.
|
|
2436
|
+
export function nativeModuleHtml(source){
|
|
2437
|
+
const structure=scanHtmlStructure(source);
|
|
2438
|
+
function withAttributes(element){
|
|
2439
|
+
const attributes=parseTagAttributes(element.open);
|
|
2440
|
+
return {
|
|
2441
|
+
...element,
|
|
2442
|
+
attributes,
|
|
2443
|
+
attribute:function attribute(name){
|
|
2444
|
+
return structuralAttribute(attributes,name,element.tag??'script');
|
|
2445
|
+
}
|
|
2446
|
+
};
|
|
2447
|
+
}
|
|
2448
|
+
return {
|
|
2449
|
+
...structure,
|
|
2450
|
+
scripts:structure.scripts.map(withAttributes),
|
|
2451
|
+
elements:structure.elements.map(withAttributes),
|
|
2452
|
+
bases:structure.bases.map(withAttributes)
|
|
2453
|
+
};
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2456
|
+
export function rewriteNativeJavaScript(source,resolveReference){
|
|
2457
|
+
return applyReferenceEdits(source,javascriptReferenceEdits(source,null,null,resolveReference));
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
export function rewriteNativeStylesheet(source,resolveReference){
|
|
2461
|
+
return applyReferenceEdits(source,cssReferenceEdits(source,null,null,
|
|
2462
|
+
function nativeStyleReference(url,_version,kind){
|
|
2463
|
+
return resolveReference({url,kind})??url;
|
|
2464
|
+
}
|
|
2465
|
+
));
|
|
2466
|
+
}
|
|
2467
|
+
|
|
2468
|
+
export function rewriteNativeSrcset(source,resolveReference){
|
|
2469
|
+
return applyReferenceEdits(source,srcsetReferenceEdits(source,null,null,
|
|
2470
|
+
function nativeSrcsetReference(url){
|
|
2471
|
+
return resolveReference({url,kind:'asset'})??url;
|
|
2472
|
+
}
|
|
2473
|
+
));
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
export function applyNativeReferenceEdits(source,edits){
|
|
2477
|
+
return applyReferenceEdits(source,edits);
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2153
2480
|
function renderManagedHtml(html,json,baseHref='../../'){
|
|
2154
2481
|
const structure=scanHtmlStructure(html);
|
|
2155
2482
|
const activeBases=structure.bases.map(base=>({
|
|
@@ -2326,6 +2653,7 @@ export async function createApplicationTestImportMapContext({
|
|
|
2326
2653
|
applicationRoot,
|
|
2327
2654
|
boundary='source',
|
|
2328
2655
|
imports={},
|
|
2656
|
+
scopes,
|
|
2329
2657
|
signal
|
|
2330
2658
|
}={}){
|
|
2331
2659
|
if(!is.string(applicationRoot)||applicationRoot.trim()===''){
|
|
@@ -2337,6 +2665,9 @@ export async function createApplicationTestImportMapContext({
|
|
|
2337
2665
|
if(imports===null||!is.object(imports)||is.array(imports)){
|
|
2338
2666
|
throw new TypeError('imports must be a plain object.');
|
|
2339
2667
|
}
|
|
2668
|
+
if (scopes !== undefined && (scopes === null || !is.object(scopes) || is.array(scopes))) {
|
|
2669
|
+
throw new TypeError('scopes must be an object.');
|
|
2670
|
+
}
|
|
2340
2671
|
throwIfAborted(signal);
|
|
2341
2672
|
const requestedApplicationRoot=path.resolve(applicationRoot);
|
|
2342
2673
|
const applicationInfo=await lstat(requestedApplicationRoot);
|
|
@@ -2355,35 +2686,48 @@ export async function createApplicationTestImportMapContext({
|
|
|
2355
2686
|
||!pathInside(canonicalApplicationRoot,canonicalBase)){
|
|
2356
2687
|
fail(`Application ${boundary} import-map base must be one physical app-owned directory.`);
|
|
2357
2688
|
}
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2689
|
+
async function selectImports(entries) {
|
|
2690
|
+
const selected = {};
|
|
2691
|
+
for (const [specifier, target] of Object.entries(entries)) {
|
|
2692
|
+
throwIfAborted(signal);
|
|
2693
|
+
if (!is.string(specifier) || specifier === '' || !is.string(target)
|
|
2694
|
+
|| !target.startsWith('./')) {
|
|
2695
|
+
fail(`Application test import-map entry is invalid: ${String(specifier)}.`);
|
|
2696
|
+
}
|
|
2697
|
+
const relative = safeRelativePath(
|
|
2698
|
+
decodeURIComponent(target.slice(2).split(/[?#]/u)[0]),
|
|
2699
|
+
`application test import-map target for ${specifier}`
|
|
2700
|
+
);
|
|
2701
|
+
if (boundary === 'source' && /^(?:dist|test)\//u.test(relative)) {
|
|
2702
|
+
fail(`Source import-map target selects another application boundary: ${specifier}.`);
|
|
2703
|
+
}
|
|
2704
|
+
const candidate = path.resolve(canonicalBase, ...relative.split('/'));
|
|
2705
|
+
const targetInfo = await lstat(candidate);
|
|
2706
|
+
const canonicalTarget = await realpath(candidate);
|
|
2707
|
+
if (targetInfo.isSymbolicLink() || !targetInfo.isFile()
|
|
2708
|
+
|| !samePath(candidate, canonicalTarget) || !pathInside(canonicalBase, canonicalTarget)) {
|
|
2709
|
+
fail(`Application test import-map target leaves its physical ${boundary} directory: ${specifier}.`);
|
|
2710
|
+
}
|
|
2711
|
+
selected[specifier] = target;
|
|
2378
2712
|
}
|
|
2379
|
-
|
|
2713
|
+
return selected;
|
|
2380
2714
|
}
|
|
2381
|
-
|
|
2715
|
+
const result = {
|
|
2382
2716
|
protocol:'arcane-test-import-map/1',
|
|
2383
2717
|
boundary,
|
|
2384
2718
|
baseURL:pathToFileURL(`${canonicalBase}${path.sep}`).href,
|
|
2385
|
-
imports:
|
|
2719
|
+
imports:await selectImports(imports)
|
|
2386
2720
|
};
|
|
2721
|
+
if (scopes !== undefined) {
|
|
2722
|
+
result.scopes = {};
|
|
2723
|
+
for (const [scope, entries] of Object.entries(scopes)) {
|
|
2724
|
+
if (scope === '' || entries === null || !is.object(entries) || is.array(entries)) {
|
|
2725
|
+
fail(`Application test import-map scope is invalid: ${scope}.`);
|
|
2726
|
+
}
|
|
2727
|
+
result.scopes[scope] = await selectImports(entries);
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
return result;
|
|
2387
2731
|
}
|
|
2388
2732
|
|
|
2389
2733
|
export async function readApplicationTestImportMapContext({
|
|
@@ -2428,16 +2772,20 @@ export async function readApplicationTestImportMapContext({
|
|
|
2428
2772
|
fail('Application test import-map artifact must contain an imports object.');
|
|
2429
2773
|
}
|
|
2430
2774
|
const installed=await readInstalledSdkLayout(resolvedWorkspaceRoot);
|
|
2431
|
-
|
|
2775
|
+
function installedApplicationTestUrl(value) {
|
|
2776
|
+
return installed && is.string(value) && value.startsWith('./')
|
|
2777
|
+
? `./${installedRuntimeTarget(value.slice(2), installed)}` : value;
|
|
2778
|
+
}
|
|
2779
|
+
const imports=Object.fromEntries(Object.entries(document.imports).map(
|
|
2432
2780
|
function installedApplicationTestTarget([specifier,target]){
|
|
2433
|
-
return [specifier,
|
|
2434
|
-
?`./${installedRuntimeTarget(target.slice(2),installed)}`:target];
|
|
2781
|
+
return [specifier,installedApplicationTestUrl(target)];
|
|
2435
2782
|
}
|
|
2436
|
-
))
|
|
2783
|
+
));
|
|
2437
2784
|
return createApplicationTestImportMapContext({
|
|
2438
2785
|
applicationRoot:resolvedWorkspaceRoot,
|
|
2439
2786
|
boundary:'source',
|
|
2440
2787
|
imports,
|
|
2788
|
+
scopes:translateImportMapScopes(document.scopes, installedApplicationTestUrl),
|
|
2441
2789
|
signal
|
|
2442
2790
|
});
|
|
2443
2791
|
}
|
|
@@ -2509,7 +2857,7 @@ function documentRelativeUrl(target, base) {
|
|
|
2509
2857
|
return `${pathname}${target.search}${target.hash}`;
|
|
2510
2858
|
}
|
|
2511
2859
|
|
|
2512
|
-
function
|
|
2860
|
+
function documentImportMap(importMap, context, baseHref, relative) {
|
|
2513
2861
|
const documentUrl = new URL(encodedUrlPath(relative), context.deployment);
|
|
2514
2862
|
// Match URL parser normalization only for resolving the base; preserve authored HTML.
|
|
2515
2863
|
const baseAddress = (baseHref ?? '').replace(/[\t\r\n]/gu, '').replace(
|
|
@@ -2545,16 +2893,20 @@ function documentImports(imports, context, baseHref, relative) {
|
|
|
2545
2893
|
return value;
|
|
2546
2894
|
}
|
|
2547
2895
|
const rebased = {};
|
|
2548
|
-
for (const [specifier, target] of Object.entries(imports)) {
|
|
2896
|
+
for (const [specifier, target] of Object.entries(importMap.imports)) {
|
|
2549
2897
|
rebased[rebaseUrl(specifier)] = rebaseUrl(target);
|
|
2550
2898
|
}
|
|
2551
|
-
|
|
2899
|
+
const result = {imports:rebased};
|
|
2900
|
+
if (importMap.scopes !== undefined) {
|
|
2901
|
+
result.scopes = translateImportMapScopes(importMap.scopes, rebaseUrl);
|
|
2902
|
+
}
|
|
2903
|
+
return result;
|
|
2552
2904
|
}
|
|
2553
2905
|
|
|
2554
|
-
function renderDocumentImportMap(html,
|
|
2906
|
+
function renderDocumentImportMap(html, importMap, state) {
|
|
2555
2907
|
const {structure, managed, firstLoad, base} = state;
|
|
2556
2908
|
const newline = html.includes('\r\n') ? '\r\n' : '\n';
|
|
2557
|
-
const json = JSON.stringify(
|
|
2909
|
+
const json = JSON.stringify(importMap, null, 2).replaceAll('<', '\\u003c');
|
|
2558
2910
|
const block = `<script type="importmap" ${MANAGED_IMPORT_MAP_ATTRIBUTE}>${newline}${json}${newline}</script>`;
|
|
2559
2911
|
const firstManaged = managed[0];
|
|
2560
2912
|
const replaceInPlace = firstManaged
|
|
@@ -2691,13 +3043,15 @@ export async function generateDocumentImportMaps({
|
|
|
2691
3043
|
const rendered = documentStates.map(
|
|
2692
3044
|
function renderSelectedDocument(document) {
|
|
2693
3045
|
throwIfAborted(signal);
|
|
2694
|
-
const
|
|
2695
|
-
|
|
3046
|
+
const importMap = documentImportMap(built, context, document.state.base?.href, document.path);
|
|
3047
|
+
const result = {
|
|
2696
3048
|
path:document.path,
|
|
2697
3049
|
filePath:document.filePath,
|
|
2698
|
-
imports,
|
|
2699
|
-
html:renderDocumentImportMap(document.html,
|
|
3050
|
+
imports:importMap.imports,
|
|
3051
|
+
html:renderDocumentImportMap(document.html, importMap, document.state)
|
|
2700
3052
|
};
|
|
3053
|
+
if (importMap.scopes !== undefined) result.scopes = importMap.scopes;
|
|
3054
|
+
return result;
|
|
2701
3055
|
}
|
|
2702
3056
|
);
|
|
2703
3057
|
const paths = [];
|
|
@@ -2721,11 +3075,13 @@ export async function generateDocumentImportMaps({
|
|
|
2721
3075
|
documentCount:documentPaths.length,
|
|
2722
3076
|
documents:rendered.map(
|
|
2723
3077
|
function documentResult(document) {
|
|
2724
|
-
|
|
3078
|
+
const result = {
|
|
2725
3079
|
path:document.path,
|
|
2726
3080
|
filePath:document.filePath,
|
|
2727
3081
|
imports:document.imports
|
|
2728
3082
|
};
|
|
3083
|
+
if (document.scopes !== undefined) result.scopes = document.scopes;
|
|
3084
|
+
return result;
|
|
2729
3085
|
}
|
|
2730
3086
|
),
|
|
2731
3087
|
committed:true
|
|
@@ -2836,6 +3192,7 @@ async function generateImportMapUnlocked({
|
|
|
2836
3192
|
excludedModules:built.excludedModules,
|
|
2837
3193
|
committed:true
|
|
2838
3194
|
};
|
|
3195
|
+
if (built.scopes !== undefined) result.scopes = built.scopes;
|
|
2839
3196
|
const completedEventError=await emit(onEvent,{
|
|
2840
3197
|
type:'import-map.completed',
|
|
2841
3198
|
appId,
|