pxt-core 7.5.2 → 7.5.5

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.
Files changed (67) hide show
  1. package/built/cli.js +61 -46
  2. package/built/pxt.js +256 -91
  3. package/built/pxtblockly.js +652 -657
  4. package/built/pxtblocks.d.ts +1 -0
  5. package/built/pxtblocks.js +98 -42
  6. package/built/pxtcompiler.js +45 -4
  7. package/built/pxtlib.d.ts +7 -2
  8. package/built/pxtlib.js +77 -39
  9. package/built/pxtpy.js +73 -2
  10. package/built/server.js +4 -0
  11. package/built/target.js +1 -1
  12. package/built/web/authcode/css/main.1cf9dc37.css +2 -0
  13. package/built/web/authcode/js/main.03da4c20.js +2 -0
  14. package/built/web/main.js +1 -1
  15. package/built/web/pxtapp.js +1 -1
  16. package/built/web/pxtasseteditor.js +1 -1
  17. package/built/web/pxtblockly.js +2 -2
  18. package/built/web/pxtblocks.js +1 -1
  19. package/built/web/pxtcompiler.js +1 -1
  20. package/built/web/pxtembed.js +2 -2
  21. package/built/web/pxtlib.js +1 -1
  22. package/built/web/pxtpy.js +1 -1
  23. package/built/web/pxtworker.js +1 -1
  24. package/built/web/react-common-authcode.css +6200 -0
  25. package/built/web/react-common-skillmap.css +1 -1
  26. package/built/web/rtlreact-common-skillmap.css +1 -1
  27. package/built/web/rtlsemantic.css +1 -1
  28. package/built/web/semantic.css +1 -1
  29. package/built/web/skillmap/css/{main.e0620cee.chunk.css → main.73b22966.chunk.css} +1 -1
  30. package/built/web/skillmap/js/{2.f7cdfd75.chunk.js → 2.3e47a285.chunk.js} +2 -2
  31. package/built/web/skillmap/js/main.2485091f.chunk.js +1 -0
  32. package/common-docs/faq.md +1 -1
  33. package/common-docs/translate.md +2 -2
  34. package/docfiles/apptracking.html +1 -1
  35. package/docfiles/tracking.html +1 -1
  36. package/localtypings/projectheader.d.ts +6 -0
  37. package/package.json +5 -3
  38. package/pxtarget.json +1 -1
  39. package/react-common/components/controls/Button.tsx +4 -1
  40. package/react-common/components/controls/EditorToggle.tsx +153 -0
  41. package/react-common/components/controls/FocusList.tsx +120 -0
  42. package/react-common/components/controls/Input.tsx +4 -4
  43. package/react-common/components/controls/Link.tsx +36 -0
  44. package/react-common/components/controls/MenuBar.tsx +5 -95
  45. package/react-common/components/controls/MenuDropdown.tsx +4 -1
  46. package/react-common/components/controls/Textarea.tsx +103 -0
  47. package/react-common/components/share/GifInfo.tsx +63 -0
  48. package/react-common/components/share/GifRecorder.tsx +97 -0
  49. package/react-common/components/share/Share.tsx +49 -0
  50. package/react-common/components/share/ShareInfo.tsx +186 -0
  51. package/react-common/components/share/SocialButton.tsx +53 -0
  52. package/react-common/styles/controls/Button.less +4 -0
  53. package/react-common/styles/controls/EditorToggle.less +271 -0
  54. package/react-common/styles/controls/Modal.less +7 -5
  55. package/react-common/styles/controls/Textarea.less +81 -0
  56. package/react-common/styles/react-common-authcode-core.less +10 -0
  57. package/react-common/styles/react-common-authcode.less +12 -0
  58. package/react-common/styles/react-common-variables.less +19 -0
  59. package/react-common/styles/react-common.less +3 -0
  60. package/react-common/styles/share/share.less +116 -0
  61. package/theme/image-editor/imageEditor.less +8 -116
  62. package/webapp/public/authcode.html +1 -0
  63. package/webapp/public/blockly/blockly_compressed.js +554 -615
  64. package/webapp/public/index.html +1 -1
  65. package/webapp/public/run.html +32 -5
  66. package/webapp/public/skillmap.html +2 -2
  67. package/built/web/skillmap/js/main.f6866fc6.chunk.js +0 -1
@@ -39,6 +39,7 @@ declare namespace pxt.blocks {
39
39
  alreadyDeclared?: BlockDeclarationType;
40
40
  firstReference?: Blockly.Block;
41
41
  isAssigned?: boolean;
42
+ isFunctionParameter?: boolean;
42
43
  }
43
44
  function compileExpression(e: Environment, b: Blockly.Block, comments: string[]): JsNode;
44
45
  interface Environment {
@@ -179,7 +179,7 @@ var pxt;
179
179
  }
180
180
  else if (b.type == "argument_reporter_array") {
181
181
  if (!tp) {
182
- tp = ground("any[]");
182
+ tp = lookup(e, b, b.getFieldValue("VALUE")).type;
183
183
  }
184
184
  }
185
185
  if (tp)
@@ -492,8 +492,14 @@ var pxt;
492
492
  // Last pass: if some variable has no type (because it was never used or
493
493
  // assigned to), just unify it with int...
494
494
  e.allVariables.forEach((v) => {
495
- if (getConcreteType(v.type).type == null)
496
- union(v.type, ground(v.type.isArrayType ? "number[]" : pNumber.type));
495
+ if (getConcreteType(v.type).type == null) {
496
+ if (!v.isFunctionParameter) {
497
+ union(v.type, ground(v.type.isArrayType ? "number[]" : pNumber.type));
498
+ }
499
+ else if (v.type.isArrayType) {
500
+ v.type.type = "any[]";
501
+ }
502
+ }
497
503
  });
498
504
  function connectionCheck(i) {
499
505
  return i.name ? i.connection && i.connection.check_ && i.connection.check_.length ? i.connection.check_[0] : "T" : undefined;
@@ -582,9 +588,31 @@ var pxt;
582
588
  function compileNumber(e, b, comments) {
583
589
  return blocks_1.H.mkNumberLiteral(extractNumber(b));
584
590
  }
591
+ function isNumericLiteral(e, b) {
592
+ if (!b)
593
+ return false;
594
+ if (b.type === "math_number" || b.type === "math_integer" || b.type === "math_number_minmax" || b.type === "math_whole_number") {
595
+ return true;
596
+ }
597
+ const blockInfo = e.stdCallTable[b.type];
598
+ if (!blockInfo)
599
+ return false;
600
+ const { comp } = blockInfo;
601
+ if (blockInfo.attrs.shim === "TD_ID" && comp.parameters.length === 1) {
602
+ const fieldValue = b.getFieldValue(comp.parameters[0].definitionName);
603
+ if (fieldValue) {
604
+ return !isNaN(parseInt(fieldValue));
605
+ }
606
+ else {
607
+ return isNumericLiteral(e, getInputTargetBlock(b, comp.parameters[0].definitionName));
608
+ }
609
+ }
610
+ return false;
611
+ }
612
+ function isLiteral(e, b) {
613
+ return isNumericLiteral(e, b) || b.type === "logic_boolean" || b.type === "text";
614
+ }
585
615
  let opToTok = {
586
- // POWER gets a special treatment because there's no operator for it in
587
- // TouchDevelop
588
616
  "ADD": "+",
589
617
  "MINUS": "-",
590
618
  "MULTIPLY": "*",
@@ -599,11 +627,21 @@ var pxt;
599
627
  "NEQ": "!=",
600
628
  "POWER": "**"
601
629
  };
630
+ function isComparisonOp(op) {
631
+ return ["LT", "LTE", "GT", "GTE", "EQ", "NEQ"].indexOf(op) !== -1;
632
+ }
602
633
  function compileArithmetic(e, b, comments) {
603
634
  let bOp = b.getFieldValue("OP");
604
635
  let left = getInputTargetBlock(b, "A");
605
636
  let right = getInputTargetBlock(b, "B");
606
637
  let args = [compileExpression(e, left, comments), compileExpression(e, right, comments)];
638
+ // Special handling for the case of comparing two literals (e.g. 0 === 5). TypeScript
639
+ // throws an error if we don't first cast to any
640
+ if (isComparisonOp(bOp) && isLiteral(e, left) && isLiteral(e, right)) {
641
+ if (blocks_1.flattenNode([args[0]]).output !== blocks_1.flattenNode([args[1]]).output) {
642
+ args = args.map(arg => blocks_1.H.mkParenthesizedExpression(blocks_1.mkGroup([arg, blocks_1.mkText(" as any")])));
643
+ }
644
+ }
607
645
  let t = returnType(e, left).type;
608
646
  if (t == pString.type) {
609
647
  if (bOp == "EQ")
@@ -711,7 +749,10 @@ var pxt;
711
749
  const stmts = getInputTargetBlock(b, "STACK");
712
750
  const argsDeclaration = b.getArguments().map(a => {
713
751
  if (a.type == "Array") {
714
- return `${escapeVarName(a.name, e)}: any[]`;
752
+ const binding = lookup(e, b, a.name);
753
+ const declaredType = getConcreteType(binding.type);
754
+ const paramType = ((declaredType === null || declaredType === void 0 ? void 0 : declaredType.type) && declaredType.type !== "Array") ? declaredType.type : "any[]";
755
+ return `${escapeVarName(a.name, e)}: ${paramType}`;
715
756
  }
716
757
  return `${escapeVarName(a.name, e)}: ${a.type}`;
717
758
  });
@@ -1859,7 +1900,7 @@ var pxt;
1859
1900
  return res;
1860
1901
  }
1861
1902
  function getEscapedCBParameters(b, stdfun, e) {
1862
- return getCBParameters(b, stdfun).map(binding => lookup(e, b, binding[0]).escapedName);
1903
+ return getCBParameters(b, stdfun).map(binding => lookup(e, b, binding.name).escapedName);
1863
1904
  }
1864
1905
  function getCBParameters(b, stdfun) {
1865
1906
  let handlerArgs = [];
@@ -1875,7 +1916,10 @@ var pxt;
1875
1916
  varName = varBlock && varBlock.getField("VAR").getText();
1876
1917
  }
1877
1918
  if (varName !== null) {
1878
- handlerArgs.push([varName, mkPoint(arg.type)]);
1919
+ handlerArgs.push({
1920
+ name: varName,
1921
+ type: mkPoint(arg.type)
1922
+ });
1879
1923
  }
1880
1924
  else {
1881
1925
  break;
@@ -1888,7 +1932,10 @@ var pxt;
1888
1932
  const varField = b.getField("HANDLER_" + arg.name);
1889
1933
  const varName = varField && varField.getText();
1890
1934
  if (varName !== null) {
1891
- handlerArgs.push([varName, mkPoint(arg.type)]);
1935
+ handlerArgs.push({
1936
+ name: varName,
1937
+ type: mkPoint(arg.type)
1938
+ });
1892
1939
  }
1893
1940
  else {
1894
1941
  break;
@@ -2091,11 +2138,7 @@ var pxt;
2091
2138
  }
2092
2139
  if (hasStatementInput(block)) {
2093
2140
  const vars = getDeclaredVariables(block, e).map(binding => {
2094
- return {
2095
- name: binding[0],
2096
- type: binding[1],
2097
- id: id++
2098
- };
2141
+ return Object.assign(Object.assign({}, binding), { id: id++ });
2099
2142
  });
2100
2143
  let parentScope = currentScope;
2101
2144
  if (vars.length) {
@@ -2179,17 +2222,37 @@ var pxt;
2179
2222
  switch (block.type) {
2180
2223
  case 'pxt_controls_for':
2181
2224
  case 'controls_simple_for':
2182
- return [[getLoopVariableField(block).getField("VAR").getText(), pNumber]];
2225
+ return [{
2226
+ name: getLoopVariableField(block).getField("VAR").getText(),
2227
+ type: pNumber
2228
+ }];
2183
2229
  case 'pxt_controls_for_of':
2184
2230
  case 'controls_for_of':
2185
- return [[getLoopVariableField(block).getField("VAR").getText(), mkPoint(null)]];
2231
+ return [{
2232
+ name: getLoopVariableField(block).getField("VAR").getText(),
2233
+ type: mkPoint(null)
2234
+ }];
2235
+ case 'function_definition':
2236
+ return block.getArguments().filter(arg => arg.type === "Array")
2237
+ .map(arg => {
2238
+ const point = mkPoint(null);
2239
+ point.isArrayType = true;
2240
+ return {
2241
+ name: arg.name,
2242
+ type: point,
2243
+ isFunctionParameter: true
2244
+ };
2245
+ });
2186
2246
  default:
2187
2247
  break;
2188
2248
  }
2189
2249
  if (isMutatingBlock(block)) {
2190
2250
  const declarations = block.mutation.getDeclaredVariables();
2191
2251
  if (declarations) {
2192
- return Object.keys(declarations).map(varName => [varName, mkPoint(declarations[varName])]);
2252
+ return Object.keys(declarations).map(varName => ({
2253
+ name: varName,
2254
+ type: mkPoint(declarations[varName])
2255
+ }));
2193
2256
  }
2194
2257
  }
2195
2258
  let stdFunc = e.stdCallTable[block.type];
@@ -4078,21 +4141,9 @@ var pxt;
4078
4141
  || (nsinfo && nsinfo.attributes.color)
4079
4142
  || pxt.toolbox.getNamespaceColor(ns)
4080
4143
  || 255;
4081
- if (fn.attributes.help) {
4082
- const helpUrl = fn.attributes.help.replace(/^\//, '');
4083
- if (/^github:/.test(helpUrl)) {
4084
- block.setHelpUrl(helpUrl);
4085
- }
4086
- else if (helpUrl !== "none") {
4087
- block.setHelpUrl("/reference/" + helpUrl);
4088
- }
4089
- }
4090
- else if (fn.pkg && !pxt.appTarget.bundledpkgs[fn.pkg]) { // added package
4091
- let anchor = fn.qName.toLowerCase().split('.');
4092
- if (anchor[0] == fn.pkg)
4093
- anchor.shift();
4094
- block.setHelpUrl(`/pkg/${fn.pkg}#${encodeURIComponent(anchor.join('-'))}`);
4095
- }
4144
+ const helpUrl = pxt.blocks.getHelpUrl(fn);
4145
+ if (helpUrl)
4146
+ block.setHelpUrl(helpUrl);
4096
4147
  block.setColour(color);
4097
4148
  let blockShape = Blockly.OUTPUT_SHAPE_ROUND;
4098
4149
  if (fn.retType == "boolean")
@@ -5428,10 +5479,13 @@ var pxt;
5428
5479
  }
5429
5480
  }
5430
5481
  xmlList[xmlList.length - 1].setAttribute('gap', '24');
5431
- if (Blockly.Blocks['variables_set']) {
5432
- let gap = Blockly.Blocks['variables_change'] ? 8 : 24;
5482
+ if (Blockly.Blocks['variables_change'] || Blockly.Blocks['variables_set']) {
5483
+ xmlList.unshift(createFlyoutGroupLabel("Your Variables"));
5484
+ }
5485
+ if (Blockly.Blocks['variables_change']) {
5486
+ let gap = Blockly.Blocks['variables_get'] ? 20 : 8;
5433
5487
  let blockText = '<xml>' +
5434
- '<block type="variables_set" gap="' + gap + '">' +
5488
+ '<block type="variables_change" gap="' + gap + '">' +
5435
5489
  Blockly.Variables.generateVariableFieldXmlString(mostRecentVariable) +
5436
5490
  '</block>' +
5437
5491
  '</xml>';
@@ -5444,16 +5498,16 @@ var pxt;
5444
5498
  value.appendChild(shadow);
5445
5499
  let field = goog.dom.createDom('field');
5446
5500
  field.setAttribute('name', 'NUM');
5447
- field.appendChild(document.createTextNode("0"));
5501
+ field.appendChild(document.createTextNode("1"));
5448
5502
  shadow.appendChild(field);
5449
5503
  block.appendChild(value);
5450
5504
  }
5451
- xmlList.push(block);
5505
+ xmlList.unshift(block);
5452
5506
  }
5453
- if (Blockly.Blocks['variables_change']) {
5454
- let gap = Blockly.Blocks['variables_get'] ? 20 : 8;
5507
+ if (Blockly.Blocks['variables_set']) {
5508
+ let gap = Blockly.Blocks['variables_change'] ? 8 : 24;
5455
5509
  let blockText = '<xml>' +
5456
- '<block type="variables_change" gap="' + gap + '">' +
5510
+ '<block type="variables_set" gap="' + gap + '">' +
5457
5511
  Blockly.Variables.generateVariableFieldXmlString(mostRecentVariable) +
5458
5512
  '</block>' +
5459
5513
  '</xml>';
@@ -5466,11 +5520,11 @@ var pxt;
5466
5520
  value.appendChild(shadow);
5467
5521
  let field = goog.dom.createDom('field');
5468
5522
  field.setAttribute('name', 'NUM');
5469
- field.appendChild(document.createTextNode("1"));
5523
+ field.appendChild(document.createTextNode("0"));
5470
5524
  shadow.appendChild(field);
5471
5525
  block.appendChild(value);
5472
5526
  }
5473
- xmlList.push(block);
5527
+ xmlList.unshift(block);
5474
5528
  }
5475
5529
  }
5476
5530
  return xmlList;
@@ -5862,6 +5916,8 @@ var pxt;
5862
5916
  const elems = oldFlyout(workspace);
5863
5917
  if (elems.length > 1) {
5864
5918
  let returnBlock = mkReturnStatementBlock();
5919
+ // Add divider
5920
+ elems.splice(1, 0, createFlyoutGroupLabel("Your Functions"));
5865
5921
  // Insert after the "make a function" button
5866
5922
  elems.splice(1, 0, returnBlock);
5867
5923
  }
@@ -32,6 +32,9 @@ var pxt;
32
32
  });
33
33
  });
34
34
  }
35
+ latestVersionAsync(repopath, config) {
36
+ return this.db.latestVersionAsync(repopath, config);
37
+ }
35
38
  loadConfigAsync(repopath, tag) {
36
39
  return this.loadAsync(repopath, tag, "pxt", (r, t) => this.db.loadConfigAsync(r, t));
37
40
  }
@@ -4620,6 +4623,8 @@ ${output}</xml>`;
4620
4623
  return getTaggedTemplateExpression(n);
4621
4624
  case SK.CallExpression:
4622
4625
  return getStatementBlock(n, undefined, undefined, true);
4626
+ case SK.AsExpression:
4627
+ return getOutputBlock(n.expression);
4623
4628
  default:
4624
4629
  error(n, pxtc.Util.lf("Unsupported syntax kind for output expression block: {0}", SK[n.kind]));
4625
4630
  break;
@@ -5500,11 +5505,14 @@ ${output}</xml>`;
5500
5505
  r.mutationChildren = [];
5501
5506
  n.parameters.forEach(p => {
5502
5507
  const paramName = p.name.getText();
5508
+ let type = normalizeType(p.type.getText());
5509
+ if (pxt.U.endsWith(type, "[]"))
5510
+ type = "Array";
5503
5511
  r.mutationChildren.push({
5504
5512
  nodeName: "arg",
5505
5513
  attributes: {
5506
5514
  name: paramName,
5507
- type: p.type.getText(),
5515
+ type,
5508
5516
  id: env.functionParamIds[name][paramName]
5509
5517
  }
5510
5518
  });
@@ -5580,11 +5588,14 @@ ${output}</xml>`;
5580
5588
  env.declaredFunctions[name].parameters.forEach((p, i) => {
5581
5589
  const paramName = p.name.getText();
5582
5590
  const argId = env.functionParamIds[name][paramName];
5591
+ let type = normalizeType(p.type.getText());
5592
+ if (pxt.U.endsWith(type, "[]"))
5593
+ type = "Array";
5583
5594
  r.mutationChildren.push({
5584
5595
  nodeName: "arg",
5585
5596
  attributes: {
5586
5597
  name: paramName,
5587
- type: p.type.getText(),
5598
+ type: type,
5588
5599
  id: argId
5589
5600
  }
5590
5601
  });
@@ -6452,7 +6463,8 @@ ${output}</xml>`;
6452
6463
  if (!type) {
6453
6464
  return pxtc.Util.lf("Function parameters must declare a type");
6454
6465
  }
6455
- if (env.opts.allowedArgumentTypes.indexOf(normalizeType(type)) === -1) {
6466
+ const normalized = normalizeType(type);
6467
+ if (env.opts.allowedArgumentTypes.indexOf(normalized) === -1 && !pxtc.U.endsWith(normalized, "[]")) {
6456
6468
  return pxtc.Util.lf("Only types that can be added in blocks can be used for function arguments");
6457
6469
  }
6458
6470
  }
@@ -6727,6 +6739,8 @@ ${output}</xml>`;
6727
6739
  return checkStatement(n, env, true, undefined);
6728
6740
  case SK.TaggedTemplateExpression:
6729
6741
  return checkTaggedTemplateExpression(n, env);
6742
+ case SK.AsExpression:
6743
+ return checkAsExpression(n);
6730
6744
  }
6731
6745
  return pxtc.Util.lf("Unsupported syntax kind for output expression block: {0}", SK[n.kind]);
6732
6746
  function checkStringLiteral(n) {
@@ -6823,6 +6837,31 @@ ${output}</xml>`;
6823
6837
  // The compiler will have already caught any invalid tags or templates
6824
6838
  return undefined;
6825
6839
  }
6840
+ function checkAsExpression(n) {
6841
+ // The only time we allow casts to decompile is in the very special case where someone has
6842
+ // written a program comparing two string, boolean, or numeric literals in blocks and
6843
+ // converted to text. e.g. 3 == 5 or true != false
6844
+ if (n.type.getText().trim() === "any" && (ts.isStringOrNumericLiteral(n.expression) ||
6845
+ n.expression.kind === SK.TrueKeyword || n.expression.kind === SK.FalseKeyword)) {
6846
+ const [parent] = getParent(n);
6847
+ if (parent.kind === SK.BinaryExpression) {
6848
+ switch (parent.operatorToken.kind) {
6849
+ case SK.EqualsEqualsToken:
6850
+ case SK.EqualsEqualsEqualsToken:
6851
+ case SK.ExclamationEqualsToken:
6852
+ case SK.ExclamationEqualsEqualsToken:
6853
+ case SK.LessThanToken:
6854
+ case SK.LessThanEqualsToken:
6855
+ case SK.GreaterThanToken:
6856
+ case SK.GreaterThanEqualsToken:
6857
+ return undefined;
6858
+ default:
6859
+ break;
6860
+ }
6861
+ }
6862
+ }
6863
+ return pxtc.Util.lf("Casting not supported in blocks");
6864
+ }
6826
6865
  function getParent(node) {
6827
6866
  if (!node.parent) {
6828
6867
  return [undefined, node];
@@ -12615,8 +12654,10 @@ ${lbl}: .short 0xffff
12615
12654
  return needsNumberConversions() ? pxtc.ir.rtcall("pxt::toInt", [e]) : e;
12616
12655
  };
12617
12656
  // c = a[i]
12618
- if (iterVar)
12657
+ if (iterVar) {
12619
12658
  proc.emitExpr(iterVar.storeByRef(pxtc.ir.rtcall(indexer, [collectionVar.loadCore(), toInt(intVarIter.loadCore())])));
12659
+ emitBrk(node.initializer);
12660
+ }
12620
12661
  flushHoistedFunctionDefinitions();
12621
12662
  emit(node.statement);
12622
12663
  proc.emitLblDirect(l.cont);
package/built/pxtlib.d.ts CHANGED
@@ -552,6 +552,7 @@ declare namespace pxt {
552
552
  multiUrl?: string;
553
553
  asseteditorUrl?: string;
554
554
  skillmapUrl?: string;
555
+ authcodeUrl?: string;
555
556
  isStatic?: boolean;
556
557
  verprefix?: string;
557
558
  }
@@ -656,6 +657,7 @@ declare namespace pxt.blocks {
656
657
  function normalizeBlock(b: string, err?: (msg: string) => void): string;
657
658
  function compileInfo(fn: pxtc.SymbolInfo): BlockCompileInfo;
658
659
  function hasHandler(fn: pxtc.SymbolInfo): boolean;
660
+ function getHelpUrl(fn: pxtc.SymbolInfo): string;
659
661
  /**
660
662
  * Returns which Blockly block type to use for an argument reporter based
661
663
  * on the specified TypeScript type.
@@ -1215,16 +1217,19 @@ declare namespace pxt.github {
1215
1217
  files: Map<string>;
1216
1218
  }
1217
1219
  interface IGithubDb {
1220
+ latestVersionAsync(repopath: string, config: PackagesConfig): Promise<string>;
1218
1221
  loadConfigAsync(repopath: string, tag: string): Promise<pxt.PackageConfig>;
1219
1222
  loadPackageAsync(repopath: string, tag: string): Promise<CachedPackage>;
1220
1223
  }
1221
1224
  function isOrgAsync(owner: string): Promise<boolean>;
1222
1225
  class MemoryGithubDb implements IGithubDb {
1226
+ private latestVersions;
1223
1227
  private configs;
1224
1228
  private packages;
1225
1229
  private proxyWithCdnLoadPackageAsync;
1226
1230
  private cacheConfig;
1227
1231
  loadConfigAsync(repopath: string, tag: string): Promise<pxt.PackageConfig>;
1232
+ latestVersionAsync(repopath: string, config: PackagesConfig): Promise<string>;
1228
1233
  loadPackageAsync(repopath: string, tag: string): Promise<CachedPackage>;
1229
1234
  private githubLoadPackageAsync;
1230
1235
  }
@@ -1260,7 +1265,7 @@ declare namespace pxt.github {
1260
1265
  function forkRepoAsync(repopath: string, commitid: string, pref?: string): Promise<string>;
1261
1266
  function listRefsAsync(repopath: string, namespace?: string, useProxy?: boolean, noCache?: boolean): Promise<string[]>;
1262
1267
  function listRefsExtAsync(repopath: string, namespace?: string, useProxy?: boolean, noCache?: boolean): Promise<RefsResult>;
1263
- function pkgConfigAsync(repopath: string, tag?: string): Promise<PackageConfig>;
1268
+ function pkgConfigAsync(repopath: string, tag: string, config: pxt.PackagesConfig): Promise<PackageConfig>;
1264
1269
  function downloadPackageAsync(repoWithTag: string, config: pxt.PackagesConfig): Promise<CachedPackage>;
1265
1270
  function downloadLatestPackageAsync(repo: ParsedRepo): Promise<{
1266
1271
  version: string;
@@ -1311,7 +1316,7 @@ declare namespace pxt.github {
1311
1316
  function toGithubDependencyPath(path: string, tag?: string): string;
1312
1317
  function isGithubId(id: string): boolean;
1313
1318
  function stringifyRepo(p: ParsedRepo): string;
1314
- function normalizeRepoId(id: string): string;
1319
+ function normalizeRepoId(id: string, defaultTag?: string): string;
1315
1320
  function join(...parts: string[]): string;
1316
1321
  function upgradedPackageReference(cfg: PackagesConfig, id: string): string;
1317
1322
  function upgradedPackageId(cfg: PackagesConfig, id: string): string;
package/built/pxtlib.js CHANGED
@@ -3909,6 +3909,25 @@ var pxt;
3909
3909
  });
3910
3910
  }
3911
3911
  blocks.hasHandler = hasHandler;
3912
+ function getHelpUrl(fn) {
3913
+ if (fn.attributes.help) {
3914
+ const helpUrl = fn.attributes.help.replace(/^\//, '');
3915
+ if (/^github:/.test(helpUrl)) {
3916
+ return helpUrl;
3917
+ }
3918
+ else if (helpUrl !== "none") {
3919
+ return "/reference/" + helpUrl;
3920
+ }
3921
+ }
3922
+ else if (fn.pkg && !pxt.appTarget.bundledpkgs[fn.pkg]) { // added package
3923
+ let anchor = fn.qName.toLowerCase().split('.');
3924
+ if (anchor[0] == fn.pkg)
3925
+ anchor.shift();
3926
+ return `/pkg/${fn.pkg}#${encodeURIComponent(anchor.join('-'))}`;
3927
+ }
3928
+ return undefined;
3929
+ }
3930
+ blocks.getHelpUrl = getHelpUrl;
3912
3931
  /**
3913
3932
  * Returns which Blockly block type to use for an argument reporter based
3914
3933
  * on the specified TypeScript type.
@@ -3920,6 +3939,9 @@ var pxt;
3920
3939
  if (varType === "boolean" || varType === "number" || varType === "string") {
3921
3940
  reporterType = `argument_reporter_${varType}`;
3922
3941
  }
3942
+ if (/^(?:Array<(?:.+)>)|(?:(?:.+)\[\])$/.test(varType)) {
3943
+ reporterType = "argument_reporter_array";
3944
+ }
3923
3945
  return reporterType;
3924
3946
  }
3925
3947
  blocks.reporterTypeForArgType = reporterTypeForArgType;
@@ -9827,6 +9849,7 @@ var pxt;
9827
9849
  github.isOrgAsync = isOrgAsync;
9828
9850
  class MemoryGithubDb {
9829
9851
  constructor() {
9852
+ this.latestVersions = {};
9830
9853
  this.configs = {};
9831
9854
  this.packages = {};
9832
9855
  }
@@ -9849,8 +9872,10 @@ var pxt;
9849
9872
  return pxt.U.clone(cfg);
9850
9873
  }
9851
9874
  async loadConfigAsync(repopath, tag) {
9852
- if (!tag)
9875
+ if (!tag) {
9876
+ pxt.debug(`dep: default to master branch`);
9853
9877
  tag = "master";
9878
+ }
9854
9879
  // cache lookup
9855
9880
  const key = `${repopath}/${tag}`;
9856
9881
  let res = this.configs[key];
@@ -9873,9 +9898,19 @@ var pxt;
9873
9898
  const cfg = await downloadTextAsync(repopath, tag, pxt.CONFIG_NAME);
9874
9899
  return this.cacheConfig(key, cfg);
9875
9900
  }
9901
+ async latestVersionAsync(repopath, config) {
9902
+ let resolved = this.latestVersions[repopath];
9903
+ if (!resolved) {
9904
+ pxt.debug(`dep: resolve latest version of ${repopath}`);
9905
+ this.latestVersions[repopath] = resolved = await pxt.github.latestVersionAsync(repopath, config, true, false);
9906
+ }
9907
+ return resolved;
9908
+ }
9876
9909
  async loadPackageAsync(repopath, tag) {
9877
- if (!tag)
9910
+ if (!tag) {
9911
+ pxt.debug(`load pkg: default to master branch`);
9878
9912
  tag = "master";
9913
+ }
9879
9914
  // try using github proxy first
9880
9915
  if (hasProxy()) {
9881
9916
  try {
@@ -10191,34 +10226,38 @@ var pxt;
10191
10226
  .then(resolveRefAsync, e => ghGetJsonAsync(`https://api.github.com/repos/${parsed.slug}/git/refs/heads/${tag}`)
10192
10227
  .then(resolveRefAsync));
10193
10228
  }
10194
- function pkgConfigAsync(repopath, tag = "master") {
10195
- return github.db.loadConfigAsync(repopath, tag);
10229
+ async function pkgConfigAsync(repopath, tag, config) {
10230
+ if (!tag)
10231
+ tag = await github.db.latestVersionAsync(repopath, config);
10232
+ return await github.db.loadConfigAsync(repopath, tag);
10196
10233
  }
10197
10234
  github.pkgConfigAsync = pkgConfigAsync;
10198
- function downloadPackageAsync(repoWithTag, config) {
10235
+ async function downloadPackageAsync(repoWithTag, config) {
10199
10236
  const p = parseRepoId(repoWithTag);
10200
10237
  if (!p) {
10201
10238
  pxt.log('Unknown GitHub syntax');
10202
- return Promise.resolve(undefined);
10239
+ return undefined;
10203
10240
  }
10204
10241
  if (isRepoBanned(p, config)) {
10205
10242
  pxt.tickEvent("github.download.banned");
10206
10243
  pxt.log('Github repo is banned');
10207
- return Promise.resolve(undefined);
10244
+ return undefined;
10208
10245
  }
10209
- return github.db.loadPackageAsync(p.fullName, p.tag)
10210
- .then(cached => {
10211
- const dv = upgradedDisablesVariants(config, repoWithTag);
10212
- if (dv) {
10213
- const cfg = pxt.Package.parseAndValidConfig(cached.files[pxt.CONFIG_NAME]);
10214
- if (cfg) {
10215
- pxt.log(`auto-disable ${dv.join(",")} due to targetconfig entry for ${repoWithTag}`);
10216
- cfg.disablesVariants = dv;
10217
- cached.files[pxt.CONFIG_NAME] = pxt.Package.stringifyConfig(cfg);
10218
- }
10246
+ // always try to upgrade unbound versions
10247
+ if (!p.tag) {
10248
+ p.tag = await github.db.latestVersionAsync(p.slug, config);
10249
+ }
10250
+ const cached = await github.db.loadPackageAsync(p.fullName, p.tag);
10251
+ const dv = upgradedDisablesVariants(config, repoWithTag);
10252
+ if (dv) {
10253
+ const cfg = pxt.Package.parseAndValidConfig(cached.files[pxt.CONFIG_NAME]);
10254
+ if (cfg) {
10255
+ pxt.log(`auto-disable ${dv.join(",")} due to targetconfig entry for ${repoWithTag}`);
10256
+ cfg.disablesVariants = dv;
10257
+ cached.files[pxt.CONFIG_NAME] = pxt.Package.stringifyConfig(cfg);
10219
10258
  }
10220
- return cached;
10221
- });
10259
+ }
10260
+ return cached;
10222
10261
  }
10223
10262
  github.downloadPackageAsync = downloadPackageAsync;
10224
10263
  async function downloadLatestPackageAsync(repo) {
@@ -10228,7 +10267,7 @@ var pxt;
10228
10267
  const repoWithTag = `${repo.fullName}#${tag}`;
10229
10268
  await pxt.github.downloadPackageAsync(repoWithTag, packageConfig);
10230
10269
  // return config
10231
- const config = await pkgConfigAsync(repo.fullName, tag);
10270
+ const config = await pkgConfigAsync(repo.fullName, tag, packageConfig);
10232
10271
  const version = `github:${repoWithTag}`;
10233
10272
  return { version, config };
10234
10273
  }
@@ -10558,14 +10597,15 @@ var pxt;
10558
10597
  }
10559
10598
  github.isGithubId = isGithubId;
10560
10599
  function stringifyRepo(p) {
10561
- return p ? "github:" + p.fullName.toLowerCase() + "#" + (p.tag || "master") : undefined;
10600
+ return p ? "github:" + p.fullName.toLowerCase() + (p.tag ? `#${p.tag}` : '') : undefined;
10562
10601
  }
10563
10602
  github.stringifyRepo = stringifyRepo;
10564
- function normalizeRepoId(id) {
10603
+ function normalizeRepoId(id, defaultTag) {
10565
10604
  const gid = parseRepoId(id);
10566
10605
  if (!gid)
10567
10606
  return undefined;
10568
- gid.tag = gid.tag || "master";
10607
+ if (!gid.tag && defaultTag)
10608
+ gid.tag = defaultTag;
10569
10609
  return stringifyRepo(gid);
10570
10610
  }
10571
10611
  github.normalizeRepoId = normalizeRepoId;
@@ -13707,22 +13747,20 @@ var pxt;
13707
13747
  && json.dependencies && Object.keys(json.dependencies).every(k => typeof json.dependencies[k] === "string")
13708
13748
  && json;
13709
13749
  }
13710
- static getConfigAsync(pkgTargetVersion, id, fullVers) {
13711
- return Promise.resolve().then(() => {
13712
- if (pxt.github.isGithubId(fullVers)) {
13713
- const repoInfo = pxt.github.parseRepoId(fullVers);
13714
- return pxt.packagesConfigAsync()
13715
- .then(config => pxt.github.repoAsync(repoInfo.fullName, config)) // Make sure repo exists and is whitelisted
13716
- .then(gitRepo => gitRepo ? pxt.github.pkgConfigAsync(repoInfo.fullName, repoInfo.tag) : null);
13717
- }
13718
- else {
13719
- // If it's not from GH, assume it's a bundled package
13720
- // TODO: Add logic for shared packages if we enable that
13721
- const updatedRef = pxt.patching.upgradePackageReference(pkgTargetVersion, id, fullVers);
13722
- const bundledPkg = pxt.appTarget.bundledpkgs[updatedRef];
13723
- return JSON.parse(bundledPkg[pxt.CONFIG_NAME]);
13724
- }
13725
- });
13750
+ static async getConfigAsync(pkgTargetVersion, id, fullVers) {
13751
+ if (pxt.github.isGithubId(fullVers)) {
13752
+ const repoInfo = pxt.github.parseRepoId(fullVers);
13753
+ const packagesConfig = await pxt.packagesConfigAsync();
13754
+ const gitRepo = await pxt.github.repoAsync(repoInfo.fullName, packagesConfig); // Make sure repo exists and is whitelisted
13755
+ return gitRepo ? await pxt.github.pkgConfigAsync(repoInfo.fullName, repoInfo.tag, packagesConfig) : null;
13756
+ }
13757
+ else {
13758
+ // If it's not from GH, assume it's a bundled package
13759
+ // TODO: Add logic for shared packages if we enable that
13760
+ const updatedRef = pxt.patching.upgradePackageReference(pkgTargetVersion, id, fullVers);
13761
+ const bundledPkg = pxt.appTarget.bundledpkgs[updatedRef];
13762
+ return JSON.parse(bundledPkg[pxt.CONFIG_NAME]);
13763
+ }
13726
13764
  }
13727
13765
  static corePackages() {
13728
13766
  const pkgs = pxt.appTarget.bundledpkgs;