Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/json viewer error display #2638

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ dist
build
_site
packages/**/lib
packages/**/workerLib
packages/semi-theme-default/css/semi.css
packages/semi-theme-default/semi.scss
public
Expand Down
22 changes: 20 additions & 2 deletions .storybook/base/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const path = require('path');
const _ = require('lodash');
const chalk = require('chalk').default;
const utils = require('./utils');

const fs = require('fs');
let AnalyzePlugin = null
if(process.env.__ENABLE_ANALYZE__ === 'true') {
AnalyzePlugin = require("@ies/semi-page-analyze-inject/src/AnalyzePlugin")
Expand Down Expand Up @@ -79,6 +79,23 @@ module.exports = {
},
]
})
rules.push({
test: /jsonWorkerManager\.ts$/,
use: [
{
loader: 'webpack-replace-loader',
options: {
search: '%WORKER_RAW%',
replace: () => {
const workFilePath = resolve('packages/semi-json-viewer-core/workerLib/worker.js');
const result = fs.readFileSync(workFilePath, 'utf-8');
const encodedResult = encodeURIComponent(result);
return encodedResult;
}
}
}
]
});
config.module.rules = rules;
config.resolve.extensions.push('.js', '.jsx', '.ts', '.tsx');
config.resolve.symlinks = false;
Expand All @@ -92,7 +109,8 @@ module.exports = {
'@douyinfe/semi-illustrations': resolve('packages/semi-illustrations/src'),
'@douyinfe/semi-animation': resolve('packages/semi-animation'),
'@douyinfe/semi-animation-react': resolve('packages/semi-animation-react'),
'@douyinfe/semi-animation-styled': resolve('packages/semi-animation-styled')
'@douyinfe/semi-animation-styled': resolve('packages/semi-animation-styled'),
'@douyinfe/semi-json-viewer-core': resolve('packages/semi-json-viewer-core/src'),
};
config.devtool = 'source-map';
// config.output.publicPath = "/storybook/"
Expand Down
21 changes: 18 additions & 3 deletions gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ exports.onCreateWebpackConfig = ({ stage, rules, loaders, plugins, actions }) =>
'semi-site-header': process.env.SEMI_SITE_HEADER || '@douyinfe/semi-site-header',
'semi-site-banner': process.env.SEMI_SITE_BANNER || '@douyinfe/semi-site-banner',
'univers-webview': process.env.SEMI_SITE_UNIVERS_WEBVIEW || resolve('packages/semi-ui'),
'@douyinfe/semi-json-viewer-core': resolve('packages/semi-json-viewer-core'),
'@douyinfe/semi-json-viewer-core': resolve('packages/semi-json-viewer-core/src'),
'@douyinfe/semi-ui': resolve('packages/semi-ui'),
'@douyinfe/semi-foundation': resolve('packages/semi-foundation'),
'@douyinfe/semi-icons': resolve('packages/semi-icons/src/'),
Expand Down Expand Up @@ -170,16 +170,31 @@ exports.onCreateWebpackConfig = ({ stage, rules, loaders, plugins, actions }) =>
},
},
},
{
test: /jsonWorkerManager\.ts$/,
use: [{
loader: 'webpack-replace-loader',
options: {
search: '%WORKER_RAW%',
replace: () => {
const workFilePath = resolve('packages/semi-json-viewer-core/workerLib/worker.js');
const result = fs.readFileSync(workFilePath, 'utf-8');
const encodedResult = encodeURIComponent(result);
return encodedResult;
}
}
}],
},
{
test: [/\.tsx?$/],
include: [path.resolve(__dirname, 'src')],
use: {
use: [{
loader: 'esbuild-loader',
options: {
loader: 'tsx', // Remove this if you're not using JSX
target: 'esnext' // Syntax to compile to (see options below for possible values)
},
},
}],
},
{
test: /\.mjs$/,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@
"webpack": "^5.77.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^3.11.2",
"webpack-replace-loader": "^5.0.1",
"webpackbar": "^5.0.0-3",
"worker-loader": "^3.0.8"
},
Expand Down
6 changes: 5 additions & 1 deletion packages/semi-foundation/jsonViewer/jsonViewer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -196,5 +196,9 @@ $module: #{$prefix}-json-viewer;
cursor: pointer;
}


&-error {
text-decoration: underline wavy var(--semi-color-danger);
text-decoration-thickness: 1px;
text-underline-position: under;
}
}
2 changes: 2 additions & 0 deletions packages/semi-json-viewer-core/script/compileLib.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@ const compile = async ()=>{
const finalRaw = mainRaw.replaceAll("%WORKER_RAW%", encodeURIComponent(workerRaw));

const saveDir = path.join(__dirname, "..", "lib");
const workerSaveDir = path.join(__dirname, "..", "workerLib");

if (!fs.existsSync(saveDir)) {
fs.mkdirSync(saveDir);
}
fs.writeFileSync(path.join(workerSaveDir, "worker.js"), workerRaw, 'utf8');
fs.writeFileSync(path.join(saveDir, "index.js"), finalRaw, 'utf8');
};

Expand Down
35 changes: 32 additions & 3 deletions packages/semi-json-viewer-core/src/model/jsonModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,22 @@ export class JSONModel {
const command = this._undoStack.pop()!;
command.undo();
this._redoStack.push(command);
this.emitter?.emit('contentChanged', command.operation);
if (!isInWorkerThread()) {
this.emitter?.emit('contentChanged', command.operation);
}
if (this._jsonWorkerManager) {
this._jsonWorkerManager
.undo()
.then(res => {
return this._jsonWorkerManager?.validate();
})
.then(result => {
this.emitter?.emit('problemsChanged', {
problems: result.problems,
root: result.root,
});
});
}
}

redo() {
Expand All @@ -195,10 +210,24 @@ export class JSONModel {
const command = this._redoStack.pop()!;
command.execute();
this._undoStack.push(command);
this.emitter?.emit('contentChanged', command.operation);
if (!isInWorkerThread()) {
this.emitter?.emit('contentChanged', command.operation);
}
if (this._jsonWorkerManager) {
this._jsonWorkerManager
.redo()
.then(res => {
return this._jsonWorkerManager?.validate();
})
.then(result => {
this.emitter?.emit('problemsChanged', {
problems: result.problems,
root: result.root,
});
});
}
}


/**
* 获取值
* @returns 值
Expand Down
2 changes: 1 addition & 1 deletion packages/semi-json-viewer-core/src/service/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ export function parseJson(jsonModel: JSONModel) {
skipUntil: Json.SyntaxKind[] = []
): T | undefined {
let start = scanner.getTokenOffset();
let end = scanner.getPosition() + scanner.getTokenLength();
let end = scanner.getTokenOffset() + scanner.getTokenLength();
if (start === end && start > 0) {
start--;
while (start > 0 && /\s/.test(text.charAt(start))) {
Expand Down
41 changes: 41 additions & 0 deletions packages/semi-json-viewer-core/src/view/error/errorWidget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Diagnostic } from '../../service/jsonTypes';
import { Emitter, getEmitter } from '../../common/emitter';
import { View } from '../view';
import { GlobalEvents } from '../../common/emitterEvents';

export class ErrorWidget {
private _view: View;
private emitter: Emitter<GlobalEvents> = getEmitter();
constructor(view: View) {
this._view = view;
this._attachEventListeners();
}

private _attachEventListeners() {
this.emitter.on('problemsChanged', (result: any) => {
this.renderErrorLine(result.problems);
});
}

private renderErrorLine(problems: Diagnostic[]) {
problems.forEach((problem: Diagnostic) => {
const { start, end } = problem.range;
const errMessage = problem.message;
this.findDomByPos(start, end, errMessage);
});
}

private findDomByPos(start: { lineNumber: number; column: number }, end: { lineNumber: number; column: number }, errMessage: string) {
const line = this._view.getLineElement(start.lineNumber);
if (!line) return;
let offset = 1;
for (let i = 0; i < line.children.length; i++) {
const child = line.children[i];
offset += child.textContent?.length || 0;
if (offset > start.column && offset <= end.column) {
const className = 'semi-json-viewer-error';
child.classList.add(className);
}
}
}
}
3 changes: 3 additions & 0 deletions packages/semi-json-viewer-core/src/view/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { ScalingCellSizeAndPositionManager } from './virtualized/ScalingCellSize
import { CompleteWidget } from './complete/completeWidget';
import { HoverWidget } from './hover/hoverWidget';
import { GlobalEvents } from '../common/emitterEvents';
import { ErrorWidget } from './error/errorWidget';
//TODO 实现ViewModel抽离代码

/**
Expand Down Expand Up @@ -45,6 +46,7 @@ export class View {
private _foldWidget: FoldWidget;
private _completeWidget: CompleteWidget;
private _hoverWidget: HoverWidget;
private _errorWidget: ErrorWidget;
private _jsonWorkerManager: JsonWorkerManager = getJsonWorkerManager();
private _tokenizationJsonModelPart: TokenizationJsonModelPart;
private _scalingCellSizeAndPositionManager: ScalingCellSizeAndPositionManager;
Expand Down Expand Up @@ -79,6 +81,7 @@ export class View {
this._editWidget = new EditWidget(this, this._jsonModel, this._selectionModel, this._foldingModel);
this._completeWidget = new CompleteWidget(this, this._jsonModel, this._selectionModel);
this._hoverWidget = new HoverWidget(this);
this._errorWidget = new ErrorWidget(this);

this._tokenizationJsonModelPart = new TokenizationJsonModelPart(this._jsonModel);

Expand Down
7 changes: 6 additions & 1 deletion packages/semi-json-viewer-core/src/worker/json.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ self.onmessage = (e: MessageEvent) => {
switch (method) {
case 'updateModel':
jsonWorker.updateModel(params.op);
result = jsonWorker.getModel()?.getValue();
break;
case 'undo':
jsonWorker.undo();
break;
case 'redo':
jsonWorker.redo();
break;
case 'format':
result = jsonWorker.format(params.options as FormattingOptions);
Expand Down
8 changes: 8 additions & 0 deletions packages/semi-json-viewer-core/src/worker/jsonWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ export class JsonWorker {
return op;
}

undo() {
this._model?.undo();
}

redo() {
this._model?.redo();
}

parse() {
if (!this._model) throw new Error('Model not initialized');
return parseJsonAst(this._model);
Expand Down
28 changes: 21 additions & 7 deletions packages/semi-json-viewer-core/src/worker/jsonWorkerManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@ import { getCurrentNameSpaceId } from '../common/nameSpace';
/**
* JsonWorkerManager 类用于管理 JSON Worker
*/
type WorkerMethod = 'init' | 'updateModel' | 'format' | 'foldRange' | 'validate';
type WorkerParams = {
value?: string;
options?: FormattingOptions;
op?: IModelContentChangeEvent | IModelContentChangeEvent[]

type WorkerService = {
init: { value: string };
updateModel: {
op: IModelContentChangeEvent | IModelContentChangeEvent[]
};
format: { options: FormattingOptions };
foldRange: Record<string, never>;
validate: Record<string, never>;
undo: Record<string, never>;
redo: Record<string, never>
};

const workerManagerMap = new Map<string, JsonWorkerManager>();
Expand All @@ -21,7 +27,7 @@ export class JsonWorkerManager {
private _callbacks: Map<number, (result: any) => void>;

constructor() {
const workerRaw = decodeURIComponent('%WORKER_RAW%');
const workerRaw = decodeURIComponent(`%WORKER_RAW%`);
const blob = new Blob([workerRaw], { type: 'application/javascript' });
const workerURL = URL.createObjectURL(blob);
this._worker = new Worker(workerURL);
Expand All @@ -38,6 +44,14 @@ export class JsonWorkerManager {
return this._sendRequest('updateModel', { op });
}

undo() {
return this._sendRequest('undo', {});
}

redo() {
return this._sendRequest('redo', {});
}

formatJson(options: FormattingOptions) {
return this._sendRequest('format', { options });
}
Expand All @@ -50,7 +64,7 @@ export class JsonWorkerManager {
return this._sendRequest('validate', {});
}

private _sendRequest(method: WorkerMethod, params: WorkerParams): Promise<any> {
private _sendRequest<T extends keyof WorkerService>(method: T, params: WorkerService[T]): Promise<any> {
return new Promise((resolve, reject) => {
const messageId = Date.now() + Math.random();
this._callbacks.set(messageId, resolve);
Expand Down
Loading