fix matomo tracking ids

add_web_container
yann300 2 years ago
parent 406910fd3c
commit 5daf41a025
  1. 8
      apps/remix-ide/src/app.js
  2. 2
      apps/remix-ide/src/app/files/fileManager.ts
  3. 39
      apps/remix-ide/src/app/files/fileProvider.js
  4. 4
      apps/remix-ide/src/app/files/workspaceFileProvider.js
  5. 191
      apps/remix-ide/src/app/plugins/web-container/terminalCodesToHtml.tsx
  6. 93
      apps/remix-ide/src/app/plugins/web-container/web-container.ts
  7. 8
      apps/remix-ide/src/assets/js/loader.js
  8. 8
      apps/remix-ide/webpack.config.js
  9. 2
      libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx
  10. 3
      package.json
  11. 15
      yarn.lock

@ -45,6 +45,7 @@ import { FileDecorator } from './app/plugins/file-decorator'
import { CodeFormat } from './app/plugins/code-format'
import { SolidityUmlGen } from './app/plugins/solidity-umlgen'
import { ContractFlattener } from './app/plugins/contractFlattener'
import { WebContainerPlugin } from './app/plugins/web-container/web-container'
const isElectron = require('is-electron')
@ -187,6 +188,9 @@ class AppComponent {
// ----------------- ContractFlattener ----------------------------
const contractFlattener = new ContractFlattener()
// ----------------- WebContainerPlugin ----------------------------
const webContainerPlugin = new WebContainerPlugin()
// ----------------- import content service ------------------------
const contentImport = new CompilerImports()
@ -302,7 +306,8 @@ class AppComponent {
search,
solidityumlgen,
contractFlattener,
solidityScript
solidityScript,
webContainerPlugin
])
// LAYOUT & SYSTEM VIEWS
@ -419,6 +424,7 @@ class AppComponent {
await this.appManager.activatePlugin(['settings'])
await this.appManager.activatePlugin(['walkthrough', 'storage', 'search', 'compileAndRun', 'recorder'])
await this.appManager.activatePlugin(['solidity-script'])
await this.appManager.activatePlugin(['web-container-plugin'])
this.appManager.on(
'filePanel',

@ -23,7 +23,7 @@ const profile = {
version: packageJson.version,
methods: ['closeAllFiles', 'closeFile', 'file', 'exists', 'open', 'writeFile', 'readFile', 'copyFile', 'copyDir', 'rename', 'mkdir',
'readdir', 'dirList', 'fileList', 'remove', 'getCurrentFile', 'getFile', 'getFolder', 'setFile', 'switchFile', 'refresh',
'getProviderOf', 'getProviderByName', 'getPathFromUrl', 'getUrlFromPath', 'saveCurrentFile', 'setBatchFiles', 'isGitRepo'],
'getProviderOf', 'getProviderByName', 'currentFileProvider', 'getPathFromUrl', 'getUrlFromPath', 'saveCurrentFile', 'setBatchFiles', 'isGitRepo'],
kind: 'file-system'
}
const errorMsg = {

@ -212,8 +212,19 @@ class FileProvider {
* @param {string} path is the folder to be copied over
* @param {Function} visitFile is a function called for each visited files
* @param {Function} visitFolder is a function called for each visited folders
* @param {Function} customSystemStructureValue is a function called for customizing the json structure values
* @param {Function} customSystemStructureKey is a function called for customizing the json structure keys
*/
async _copyFolderToJsonInternal (path, visitFile, visitFolder) {
async _copyFolderToJsonInternal (path, visitFile, visitFolder, customSystemStructureValue, customSystemStructureKey) {
customSystemStructureKey = customSystemStructureKey || function (path) { return path }
customSystemStructureValue = customSystemStructureValue || function (type, content) {
if (type === 'folder') {
return { children: content }
} else if (type === 'file') {
return { content }
}
return content
}
visitFile = visitFile || function () { /* do nothing. */ }
visitFolder = visitFolder || function () { /* do nothing. */ }
@ -225,15 +236,16 @@ class FileProvider {
visitFolder({ path })
if (items.length !== 0) {
for (const item of items) {
const file = {}
let file = {}
const curPath = `${path}${path.endsWith('/') ? '' : '/'}${item}`
if ((await window.remixFileSystem.stat(curPath)).isDirectory()) {
file.children = await this._copyFolderToJsonInternal(curPath, visitFile, visitFolder)
file = customSystemStructureValue('folder', await this._copyFolderToJsonInternal(curPath, visitFile, visitFolder, customSystemStructureValue, customSystemStructureKey))
} else {
file.content = await window.remixFileSystem.readFile(curPath, 'utf8')
visitFile({ path: curPath, content: file.content })
const content = await window.remixFileSystem.readFile(curPath, 'utf8')
file = customSystemStructureValue('file', content, item)
visitFile({ folder: path, path: curPath, name: item, content })
}
json[curPath] = file
json[customSystemStructureKey(curPath)] = file
}
}
} catch (e) {
@ -249,11 +261,22 @@ class FileProvider {
* @param {string} path is the folder to be copied over
* @param {Function} visitFile is a function called for each visited files
* @param {Function} visitFolder is a function called for each visited folders
* @param {Function} customSystemStructureValue is a function called for customizing the json structure
* @param {Function} customSystemStructureKey is a function called for customizing the json structure keys
*/
async copyFolderToJson (path, visitFile, visitFolder) {
async copyFolderToJson (path, visitFile, visitFolder, customSystemStructureValue, customSystemStructureKey) {
customSystemStructureKey = customSystemStructureKey || function (path) { return path }
customSystemStructureValue = customSystemStructureValue || function (type, content) {
if (type === 'folder') {
return { children: content }
} else if (type === 'file') {
return { content }
}
return content
}
visitFile = visitFile || function () { /* do nothing. */ }
visitFolder = visitFolder || function () { /* do nothing. */ }
return await this._copyFolderToJsonInternal(path, visitFile, visitFolder)
return await this._copyFolderToJsonInternal(path, visitFile, visitFolder, customSystemStructureValue, customSystemStructureKey)
}
async removeFile (path) {

@ -53,7 +53,7 @@ class WorkspaceFileProvider extends FileProvider {
})
}
async copyFolderToJson (directory, visitFile, visitFolder) {
async copyFolderToJson (directory, visitFile, visitFolder, customSystemStructureValue, customSystemStructureKey) {
visitFile = visitFile || function () { /* do nothing. */ }
visitFolder = visitFolder || function () { /* do nothing. */ }
const regex = new RegExp(`.workspaces/${this.workspace}/`, 'g')
@ -61,7 +61,7 @@ class WorkspaceFileProvider extends FileProvider {
visitFile({ path: path.replace(regex, ''), content })
}, ({ path }) => {
visitFolder({ path: path.replace(regex, '') })
})
}, customSystemStructureValue, customSystemStructureKey)
json = JSON.stringify(json).replace(regex, '')
return JSON.parse(json)
}

@ -0,0 +1,191 @@
import Anser, { AnserJsonEntry } from "anser";
import { escapeCarriageReturn } from "escape-carriage";
import * as React from "react";
/**
* Converts ANSI strings into JSON output.
* @name ansiToJSON
* @function
* @param {String} input The input string.
* @param {boolean} use_classes If `true`, HTML classes will be appended
* to the HTML output.
* @return {Array} The parsed input.
*/
function ansiToJSON(
input: string,
use_classes: boolean = false
): AnserJsonEntry[] {
input = escapeCarriageReturn(fixBackspace(input));
return Anser.ansiToJson(input, {
json: true,
remove_empty: true,
use_classes,
});
}
/**
* Create a class string.
* @name createClass
* @function
* @param {AnserJsonEntry} bundle
* @return {String} class name(s)
*/
function createClass(bundle: AnserJsonEntry): string | null {
let classNames: string = "";
if (bundle.bg) {
classNames += `${bundle.bg}-bg `;
}
if (bundle.fg) {
classNames += `${bundle.fg}-fg `;
}
if (bundle.decoration) {
classNames += `ansi-${bundle.decoration} `;
}
if (classNames === "") {
return null;
}
classNames = classNames.substring(0, classNames.length - 1);
return classNames;
}
/**
* Create the style attribute.
* @name createStyle
* @function
* @param {AnserJsonEntry} bundle
* @return {Object} returns the style object
*/
function createStyle(bundle: AnserJsonEntry): React.CSSProperties {
const style: React.CSSProperties = {};
if (bundle.bg) {
style.backgroundColor = `rgb(${bundle.bg})`;
}
if (bundle.fg) {
style.color = `rgb(${bundle.fg})`;
}
switch (bundle.decoration) {
case 'bold':
style.fontWeight = 'bold';
break;
case 'dim':
style.opacity = '0.5';
break;
case 'italic':
style.fontStyle = 'italic';
break;
case 'hidden':
style.visibility = 'hidden';
break;
case 'strikethrough':
style.textDecoration = 'line-through';
break;
case 'underline':
style.textDecoration = 'underline';
break;
case 'blink':
style.textDecoration = 'blink';
break;
default:
break;
}
return style;
}
/**
* Converts an Anser bundle into a React Node.
* @param linkify whether links should be converting into clickable anchor tags.
* @param useClasses should render the span with a class instead of style.
* @param bundle Anser output.
* @param key
*/
function convertBundleIntoReact(
linkify: boolean,
useClasses: boolean,
bundle: AnserJsonEntry,
key: number
): JSX.Element {
const style = useClasses ? null : createStyle(bundle);
const className = useClasses ? createClass(bundle) : null;
if (!linkify) {
return React.createElement(
"span",
{ style, key, className },
bundle.content
);
}
const content: React.ReactNode[] = [];
const linkRegex = /(\s|^)(https?:\/\/(?:www\.|(?!www))[^\s.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/g;
let index = 0;
let match: RegExpExecArray | null;
while ((match = linkRegex.exec(bundle.content)) !== null) {
const [, pre, url] = match;
const startIndex = match.index + pre.length;
if (startIndex > index) {
content.push(bundle.content.substring(index, startIndex));
}
// Make sure the href we generate from the link is fully qualified. We assume http
// if it starts with a www because many sites don't support https
const href = url.startsWith("www.") ? `http://${url}` : url;
content.push(
React.createElement(
"a",
{
key: index,
href,
target: "_blank",
},
`${url}`
)
);
index = linkRegex.lastIndex;
}
if (index < bundle.content.length) {
content.push(bundle.content.substring(index));
}
return React.createElement("span", { style, key, className }, content);
}
declare interface Props {
children?: string;
linkify?: boolean;
className?: string;
useClasses?: boolean;
}
export default function Ansi(props: Props): JSX.Element {
const { className, useClasses, children, linkify } = props;
return React.createElement(
"code",
{ className },
ansiToJSON(children ?? "", useClasses ?? false).map(
convertBundleIntoReact.bind(null, linkify ?? false, useClasses ?? false)
)
);
}
// This is copied from the Jupyter Classic source code
// notebook/static/base/js/utils.js to handle \b in a way
// that is **compatible with Jupyter classic**. One can
// argue that this behavior is questionable:
// https://stackoverflow.com/questions/55440152/multiple-b-doesnt-work-as-expected-in-jupyter#
function fixBackspace(txt: string) {
let tmp = txt;
do {
txt = tmp;
// Cancel out anything-but-newline followed by backspace
tmp = txt.replace(/[^\n]\x08/gm, "");
} while (tmp.length < txt.length);
return txt;
}

@ -0,0 +1,93 @@
import { Plugin } from '@remixproject/engine'
import { WebContainer } from '@webcontainer/api'
import * as ts from "typescript";
import Ansi from "./terminalCodesToHtml"
import { logBuilder } from "@remix-ui/helper"
const profile = {
name: 'web-container-plugin',
displayName: 'WebContainerPlugin',
description: 'WebContainerPlugin',
methods: ['execute'],
events: []
}
export class WebContainerPlugin extends Plugin {
webcontainerInstance: WebContainer
constructor () {
super(profile)
WebContainer.boot().then((webcontainerInstance: WebContainer) => {
this.webcontainerInstance = webcontainerInstance
}).catch((error) => {
console.error(error)
})
}
async execute (script: string, filePath: string) {
const fileProvider = await this.call('fileManager', 'currentFileProvider')
if (!fileProvider.copyFolderToJson) throw new Error('provider does not support copyFolderToJson')
const files = await fileProvider.copyFolderToJson('/', null, null, (type, content, item) => {
if (type === 'folder') {
return { directory: content }
} else if (type === 'file') {
if (item.endsWith('.ts')) {
const output: ts.TranspileOutput = ts.transpileModule(content, {
// moduleName: filePath,
compilerOptions: {
target: ts.ScriptTarget.ES2015,
module: ts.ModuleKind.CommonJS,
esModuleInterop: true,
}})
content = output.outputText
}
return { file: { contents: content } }
}
return content
}, (path) => {
if (!path) return path
path = path.split('/')
return stripOutExtension(path[path.length - 1])
})
console.log(files)
this.webcontainerInstance.mount(files)
await this.installDependencies()
const fileName = stripOutExtension(filePath)
let contentToRun = await this.webcontainerInstance.fs.readFile(fileName, 'utf8')
await this.webcontainerInstance.fs.writeFile(fileName, this.injectRemix(contentToRun), 'utf8')
const run = await this.webcontainerInstance.spawn('node', [stripOutExtension(filePath)])
const self = this
run.output.pipeTo(new WritableStream({
write(data) {
self.call('terminal', 'logHtml', Ansi({children: data}))
}
}));
}
async installDependencies() {
// Install dependencies
const installProcess = await this.webcontainerInstance.spawn('npm', ['install']);
const self = this
installProcess.output.pipeTo(new WritableStream({
write(data) {
self.call('terminal', 'logHtml', Ansi({children: data}) )
}
}))
// Wait for install command to exit
return installProcess.exit;
}
injectRemix (contentToRun) {
return `
global.remix = {
test: () => {
console.log('iii')
}
};${contentToRun}`
}
}
const stripOutExtension = (path) => {
if (!path.endsWith('.js') && !path.endsWith('.ts')) return path
if (!path) return path
return path.replace('.js', '').replace('.ts', '')
}

@ -6,10 +6,10 @@ const domains = {
}
const domainsSecondaryTracker = {
'remix-alpha.ethereum.org': 12,
'remix-beta.ethereum.org': 10,
'remix.ethereum.org': 8,
'6fd22d6fe5549ad4c4d8fd3ca0b7816b.mod': 20 // remix desktop
'remix-alpha.ethereum.org': 27,
'remix-beta.ethereum.org': 25,
'remix.ethereum.org': 23,
'6fd22d6fe5549ad4c4d8fd3ca0b7816b.mod': 35 // remix desktop
}
if (domains[window.location.hostname]) {

@ -5,6 +5,7 @@ const CopyPlugin = require("copy-webpack-plugin")
const version = require('../../package.json').version
const fs = require('fs')
const TerserPlugin = require("terser-webpack-plugin")
const webpackMerge = require('webpack-merge');
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
const axios = require('axios')
@ -128,6 +129,13 @@ module.exports = composePlugins(withNx(), withReact(), (config) => {
ignored: /node_modules/
}
webpackMerge.merge(config, { devServer: {
headers: {
'Cross-Origin-Embedder-Policy': 'require-corp',
'Cross-Origin-Opener-Policy': 'same-origin'
}
}})
return config;
});

@ -165,7 +165,7 @@ export const TabsUI = (props: TabsUIProps) => {
const path = active().substr(active().indexOf('/') + 1, active().length)
const content = await props.plugin.call('fileManager', "readFile", path)
if (tabsState.currentExt === 'js' || tabsState.currentExt === 'ts') {
await props.plugin.call('scriptRunner', 'execute', content, path)
await props.plugin.call('web-container-plugin', 'execute', content, path)
_paq.push(['trackEvent', 'editor', 'clickRunFromEditor', tabsState.currentExt])
} else if (tabsState.currentExt === 'sol' || tabsState.currentExt === 'yul') {
await props.plugin.call('solidity', 'compile', path)

@ -143,6 +143,8 @@
"@web3modal/ethereum": "^2.2.2",
"@web3modal/react": "^2.2.2",
"@web3modal/standalone": "^2.2.2",
"@webcontainer/api": "^1.1.4",
"anser": "^2.1.1",
"ansi-gray": "^0.1.1",
"async": "^2.6.2",
"axios": "1.1.2",
@ -156,6 +158,7 @@
"core-js": "^3.6.5",
"deep-equal": "^1.0.1",
"document-register-element": "1.13.1",
"escape-carriage": "^1.3.1",
"eslint-config-prettier": "^8.5.0",
"ethers": "^5",
"ethjs-util": "^0.1.6",

@ -6942,6 +6942,11 @@
"@webassemblyjs/ast" "1.11.1"
"@xtuc/long" "4.2.2"
"@webcontainer/api@^1.1.4":
version "1.1.4"
resolved "https://registry.yarnpkg.com/@webcontainer/api/-/api-1.1.4.tgz#9447d40495e8055747fb02e9f7ccc093c3cce9ae"
integrity sha512-JjGQl25+QzuHOKLKr5QX0dAvqOFLw06YY47eWKMwkxz1otfYPtuhTRRjascqMLxGbLoRF6i1idV+vlInp5gwvA==
"@webpack-cli/configtest@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.2.0.tgz#7b20ce1c12533912c3b217ea68262365fa29a6f5"
@ -7265,6 +7270,11 @@ align-text@^0.1.1, align-text@^0.1.3:
longest "^1.0.1"
repeat-string "^1.5.2"
anser@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/anser/-/anser-2.1.1.tgz#8afae28d345424c82de89cc0e4d1348eb0c5af7c"
integrity sha512-nqLm4HxOTpeLOxcmB3QWmV5TcDFhW9y/fyQ+hivtDFcK4OQ+pQ5fzPnXHM1Mfcm0VkLtvVi1TCPr++Qy0Q/3EQ==
ansi-align@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-1.1.0.tgz#2f0c1658829739add5ebb15e6b0c6e3423f016ba"
@ -12417,6 +12427,11 @@ escalade@^3.1.1:
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escape-carriage@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/escape-carriage/-/escape-carriage-1.3.1.tgz#842658e5422497b1232585e517dc813fc6a86170"
integrity sha512-GwBr6yViW3ttx1kb7/Oh+gKQ1/TrhYwxKqVmg5gS+BK+Qe2KrOa/Vh7w3HPBvgGf0LfcDGoY9I6NHKoA5Hozhw==
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"

Loading…
Cancel
Save