mirror of https://github.com/msgbyte/tailchat
chore: use source-ref
parent
2371c90f07
commit
27fe626000
@ -1 +0,0 @@
|
||||
lib
|
@ -1 +0,0 @@
|
||||
## source-ref for webpack loader
|
@ -1,37 +0,0 @@
|
||||
{
|
||||
"name": "rollup-plugin-source-ref",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"prepare": "tsc"
|
||||
},
|
||||
"keywords": [
|
||||
"sourcecode",
|
||||
"pointer",
|
||||
"webpack"
|
||||
],
|
||||
"author": "moonrailgun",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/babel__generator": "^7.6.4",
|
||||
"@types/babel__traverse": "^7.17.1",
|
||||
"@types/node": "^15.12.5",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"rollup": "^2.75.0",
|
||||
"ts-node": "^10.0.0",
|
||||
"typescript": "^4.5.2",
|
||||
"webpack": "^5.72.0",
|
||||
"webpack-test-utils": "^1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/generator": "^7.17.7",
|
||||
"@babel/parser": "^7.17.7",
|
||||
"@babel/traverse": "^7.17.3",
|
||||
"@babel/types": "^7.17.10"
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
import type { Plugin } from 'rollup';
|
||||
import { parse } from '@babel/parser';
|
||||
import traverse from '@babel/traverse';
|
||||
import generate from '@babel/generator';
|
||||
import {
|
||||
isJSXIdentifier,
|
||||
isJSXMemberExpression,
|
||||
jsxAttribute,
|
||||
jsxIdentifier,
|
||||
stringLiteral,
|
||||
} from '@babel/types';
|
||||
|
||||
const TRACE_ID = 'data-source';
|
||||
|
||||
export default function sourceRef(): Plugin {
|
||||
return {
|
||||
name: 'source-ref',
|
||||
transform(code, id) {
|
||||
const filepath = id;
|
||||
|
||||
const ast = parse(code, {
|
||||
sourceType: 'module',
|
||||
plugins: ['jsx', 'typescript'],
|
||||
});
|
||||
|
||||
traverse(ast, {
|
||||
JSXOpeningElement(path) {
|
||||
const location = path.node.loc;
|
||||
if (!location) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(location)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const name = path.node.name;
|
||||
if (isJSXIdentifier(name) && name.name === 'Fragment') {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
isJSXMemberExpression(name) &&
|
||||
name.property.name === 'Fragment'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const line = location.start.line;
|
||||
const col = location.start.column;
|
||||
|
||||
const attrs = path.node.attributes;
|
||||
for (let i = 0; i < attrs.length; i++) {
|
||||
const attr = attrs[i];
|
||||
if (attr.type === 'JSXAttribute' && attr.name.name === TRACE_ID) {
|
||||
// existed
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const traceId = `${filepath}:${line}:${col}`;
|
||||
|
||||
attrs.push(
|
||||
jsxAttribute(jsxIdentifier(TRACE_ID), stringLiteral(traceId))
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const res = generate(ast);
|
||||
|
||||
return { code: res.code, map: res.map };
|
||||
},
|
||||
};
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"module": "commonjs",
|
||||
"target": "ES5",
|
||||
"lib": ["ESNext"],
|
||||
"declaration": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
@ -1 +0,0 @@
|
||||
lib
|
@ -1 +0,0 @@
|
||||
## source-ref for webpack loader
|
@ -1,37 +0,0 @@
|
||||
{
|
||||
"name": "source-ref-loader",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"prepare": "tsc",
|
||||
"test": "ts-node ./test/index.ts"
|
||||
},
|
||||
"keywords": [
|
||||
"sourcecode",
|
||||
"pointer",
|
||||
"webpack"
|
||||
],
|
||||
"author": "moonrailgun",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/babel__generator": "^7.6.4",
|
||||
"@types/babel__traverse": "^7.17.1",
|
||||
"@types/node": "^15.12.5",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"ts-node": "^10.0.0",
|
||||
"typescript": "^4.5.2",
|
||||
"webpack": "^5.72.0",
|
||||
"webpack-test-utils": "^1.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/generator": "^7.17.7",
|
||||
"@babel/parser": "^7.17.7",
|
||||
"@babel/traverse": "^7.17.3",
|
||||
"@babel/types": "^7.17.10"
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
import type { LoaderContext } from 'webpack';
|
||||
import { parse } from '@babel/parser';
|
||||
import traverse from '@babel/traverse';
|
||||
import generate from '@babel/generator';
|
||||
import {
|
||||
isJSXIdentifier,
|
||||
isJSXMemberExpression,
|
||||
jsxAttribute,
|
||||
jsxIdentifier,
|
||||
stringLiteral,
|
||||
} from '@babel/types';
|
||||
|
||||
const TRACE_ID = 'data-source';
|
||||
|
||||
async function loader(this: LoaderContext<any>, source: string): Promise<void> {
|
||||
const done = this.async();
|
||||
|
||||
const { available } = this.getOptions();
|
||||
if (!available) {
|
||||
// skip if not
|
||||
done(null, source);
|
||||
return;
|
||||
}
|
||||
|
||||
const ast = parse(source, {
|
||||
sourceType: 'module',
|
||||
plugins: ['jsx', 'typescript'],
|
||||
});
|
||||
const filepath = this.resourcePath;
|
||||
if (filepath.includes('node_modules')) {
|
||||
done(null, source);
|
||||
return;
|
||||
}
|
||||
|
||||
traverse(ast, {
|
||||
JSXOpeningElement(path) {
|
||||
const location = path.node.loc;
|
||||
if (!location) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(location)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const name = path.node.name;
|
||||
if (isJSXIdentifier(name) && name.name === 'Fragment') {
|
||||
return;
|
||||
}
|
||||
if (isJSXMemberExpression(name) && name.property.name === 'Fragment') {
|
||||
return;
|
||||
}
|
||||
|
||||
const line = location.start.line;
|
||||
const col = location.start.column;
|
||||
|
||||
const attrs = path.node.attributes;
|
||||
for (let i = 0; i < attrs.length; i++) {
|
||||
const attr = attrs[i];
|
||||
if (attr.type === 'JSXAttribute' && attr.name.name === TRACE_ID) {
|
||||
// existed
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const traceId = `${filepath}:${line}:${col}`;
|
||||
|
||||
attrs.push(jsxAttribute(jsxIdentifier(TRACE_ID), stringLiteral(traceId)));
|
||||
},
|
||||
});
|
||||
|
||||
const code = generate(ast).code;
|
||||
|
||||
done(null, code);
|
||||
}
|
||||
|
||||
export default loader;
|
@ -1,20 +0,0 @@
|
||||
export const tsx = {
|
||||
'/src/index.js': `
|
||||
import Foo, { HelloWorld } from './foo.tsx'
|
||||
export default [
|
||||
HelloWorld,
|
||||
(new Foo()).render(),
|
||||
];
|
||||
`,
|
||||
|
||||
'/src/foo.tsx': `
|
||||
export const HelloWorld = <><div>hello world</div></>;
|
||||
export const HelloWorld2 = <React.Fragment><div>hello world</div></React.Fragment>;
|
||||
export const HelloWorld3 = <Fragment><div>hello world</div></Fragment>;
|
||||
export default class Foo {
|
||||
render() {
|
||||
return <div className="class-name">content</div>
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
@ -1,17 +0,0 @@
|
||||
import { build } from 'webpack-test-utils';
|
||||
import * as fixtures from './fixtures';
|
||||
import { configureLoader } from './utils';
|
||||
|
||||
async function test() {
|
||||
const built = await build(fixtures.tsx, (config) => {
|
||||
configureLoader(config);
|
||||
|
||||
console.log('configureLoader(config);', config.module.rules);
|
||||
});
|
||||
|
||||
console.log('usage:', built.stats.endTime - built.stats.startTime, 'ms');
|
||||
console.log('errors:', built.stats.compilation.errors.length);
|
||||
// console.log(built.stats.compilation.errors);
|
||||
}
|
||||
|
||||
test();
|
@ -1,18 +0,0 @@
|
||||
import type { Configuration } from 'webpack';
|
||||
import type { DefaultWebpackConfig } from 'webpack-test-utils';
|
||||
|
||||
const loaderPath = require.resolve('../src/index.ts');
|
||||
|
||||
export function configureLoader(config: DefaultWebpackConfig & Configuration) {
|
||||
config.resolveLoader.alias = {
|
||||
'source-ref-loader': loaderPath,
|
||||
};
|
||||
|
||||
config.module.rules.push({
|
||||
test: /\.tsx$/,
|
||||
loader: 'source-ref-loader',
|
||||
options: {
|
||||
available: true,
|
||||
},
|
||||
});
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"module": "commonjs",
|
||||
|
||||
"target": "ES2018",
|
||||
"lib": ["ES2018"],
|
||||
|
||||
"declaration": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
@ -1 +0,0 @@
|
||||
declare module 'source-ref-open-vscode' {}
|
@ -1,223 +0,0 @@
|
||||
(function (win, doc) {
|
||||
const sourceMap = {};
|
||||
const sourceMapReverse = {};
|
||||
let cursor = 0;
|
||||
let timer = null;
|
||||
|
||||
function openVscode(node) {
|
||||
let path = null;
|
||||
if (node.dataset.sid) {
|
||||
path = sidToURI(node.dataset.sid);
|
||||
}
|
||||
if (node.dataset.source) {
|
||||
path = 'vscode://file/' + node.dataset.source;
|
||||
}
|
||||
if (!path) {
|
||||
return console.warn('Not found data-source');
|
||||
}
|
||||
win.location.href = path;
|
||||
}
|
||||
function sourceToId(node) {
|
||||
if (!node.dataset.source) return;
|
||||
const source = node.dataset.source;
|
||||
const splits = source.split(':');
|
||||
const column = splits.pop();
|
||||
const row = splits.pop();
|
||||
const file = splits.join(':');
|
||||
|
||||
if (!sourceMap[file]) {
|
||||
cursor++;
|
||||
sourceMap[file] = cursor;
|
||||
sourceMapReverse[cursor] = file;
|
||||
}
|
||||
const id = sourceMap[file];
|
||||
node.removeAttribute('data-source');
|
||||
node.setAttribute('data-sid', `${id}:${row}:${column}`);
|
||||
}
|
||||
function sidToURI(sid) {
|
||||
const [id, row, column] = sid.split(':');
|
||||
const path =
|
||||
'vscode://file/' + sourceMapReverse[id] + ':' + row + ':' + column;
|
||||
return path;
|
||||
}
|
||||
|
||||
class Selector {
|
||||
constructor(node) {
|
||||
this.sids = [];
|
||||
this.containerId = '__source-ref-panel';
|
||||
this.getAncestorSids = (node) => {
|
||||
const sids = [];
|
||||
let cur = node;
|
||||
while (cur !== doc.body) {
|
||||
if (cur.dataset.sid) {
|
||||
sids.push(cur.dataset.sid);
|
||||
}
|
||||
cur = cur.parentElement;
|
||||
}
|
||||
return sids;
|
||||
};
|
||||
this.focusBlock = null;
|
||||
this.setFocusBlock = (target) => {
|
||||
if (target === null) {
|
||||
// clear if target is null
|
||||
if (this.focusBlock) {
|
||||
doc.body.removeChild(this.focusBlock);
|
||||
this.focusBlock = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.focusBlock) {
|
||||
this.focusBlock = doc.createElement('div');
|
||||
this.focusBlock.className = '__source-ref-mask';
|
||||
this.focusBlock.style.position = 'absolute';
|
||||
this.focusBlock.style.backgroundColor = 'rgba(134, 185, 242, 0.5)';
|
||||
|
||||
doc.body.appendChild(this.focusBlock);
|
||||
}
|
||||
|
||||
const rect = target.getBoundingClientRect();
|
||||
|
||||
this.focusBlock.style.height = rect.height + 'px';
|
||||
this.focusBlock.style.width = rect.width + 'px';
|
||||
this.focusBlock.style.left = rect.x + 'px';
|
||||
this.focusBlock.style.top = rect.y + 'px';
|
||||
};
|
||||
this.getContainer = () => {
|
||||
const container = doc.getElementById(this.containerId);
|
||||
if (!container) {
|
||||
const div = doc.createElement('div');
|
||||
div.id = this.containerId;
|
||||
doc.body.appendChild(div);
|
||||
|
||||
// Add dom red border on hover
|
||||
div.addEventListener('mouseover', (e) => {
|
||||
const node = e.target;
|
||||
if (node.dataset.tid) {
|
||||
const target = doc.querySelector(
|
||||
`[data-sid="${node.dataset.tid}"]`
|
||||
);
|
||||
if (target) {
|
||||
target.classList.add('__source-ref-selected');
|
||||
this.setFocusBlock(target);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Remove dom red border when leave
|
||||
div.addEventListener('mouseout', (e) => {
|
||||
const node = e.target;
|
||||
if (node.dataset.tid) {
|
||||
const target = doc.querySelector(
|
||||
`[data-sid="${node.dataset.tid}"]`
|
||||
);
|
||||
if (target) {
|
||||
target.classList.remove('__source-ref-selected');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const close = () => {
|
||||
this.setFocusBlock(null);
|
||||
doc.body.removeChild(div);
|
||||
};
|
||||
|
||||
// click event
|
||||
div.addEventListener('click', (e) => {
|
||||
const node = e.target;
|
||||
const command = node.dataset.command;
|
||||
switch (command) {
|
||||
case 'close': {
|
||||
e.stopPropagation();
|
||||
close();
|
||||
return;
|
||||
}
|
||||
default:
|
||||
console.warn('Unknown command', command);
|
||||
}
|
||||
});
|
||||
|
||||
// keyboard event
|
||||
function escKeyHandler(e) {
|
||||
if (e.key === 'Escape') {
|
||||
e.stopPropagation();
|
||||
close();
|
||||
doc.removeEventListener('keydown', escKeyHandler);
|
||||
}
|
||||
}
|
||||
doc.addEventListener('keydown', escKeyHandler);
|
||||
|
||||
return div;
|
||||
}
|
||||
return container;
|
||||
};
|
||||
this.renderHTML = () => {
|
||||
const html = `
|
||||
<div style="
|
||||
position: fixed;
|
||||
background: white;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 9999;
|
||||
opacity: 0.6;
|
||||
border-radius: 0 10px 0 0;
|
||||
">
|
||||
<div style="cursor:pointer;margin:10px;text-align:right;font-size:18px;" data-command="close">X</div>
|
||||
${this.sids
|
||||
.map((sid) => {
|
||||
const uri = sidToURI(sid);
|
||||
// 这里加了一个左向省略,暂时没用上,先放着
|
||||
return `<a href="${uri}" style="
|
||||
display: block;
|
||||
margin: 10px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
direction: rtl;
|
||||
text-align: left;
|
||||
" data-tid="${sid}">source-ref: ${uri}</a>`;
|
||||
})
|
||||
.join('')}
|
||||
</div>
|
||||
`;
|
||||
const container = this.getContainer();
|
||||
container.innerHTML = html;
|
||||
};
|
||||
this.sids = this.getAncestorSids(node);
|
||||
}
|
||||
}
|
||||
function init() {
|
||||
win.vscode = (node = win.$0) => {
|
||||
openVscode(node);
|
||||
};
|
||||
doc.body.addEventListener(
|
||||
'click',
|
||||
(e) => {
|
||||
if (e.altKey) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const selector = new Selector(e.target);
|
||||
selector.renderHTML();
|
||||
}
|
||||
},
|
||||
true
|
||||
);
|
||||
const mo = new MutationObserver(() => {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
timer = setTimeout(() => {
|
||||
// recal sid
|
||||
doc
|
||||
.querySelectorAll('[data-source]')
|
||||
.forEach((node) => sourceToId(node));
|
||||
}, 500);
|
||||
});
|
||||
mo.observe(doc.body, {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
init();
|
||||
})(window, document);
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"name": "source-ref-open-vscode",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "moonrailgun",
|
||||
"license": "MIT"
|
||||
}
|
Loading…
Reference in New Issue