I'm using TypeScript with validate-value which uses ajv under the hood. I want to create validation schemas for filters similiar to MongoDB operators.
Each schema should have its own file but since it's possible to nest one filter into another I'm creating a circular reference before initializing the schemas. So I'm getting the error
ReferenceError: Cannot access 'filterSchema' before initialization
How to reproduce the problem with plain Node and JS:
package.json
{
"type": "module",
"scripts": {
"dev": "node main.js"
}
}
main.js
import { filterSchema } from "./filterSchemas/filterSchema.js";
console.log(filterSchema);
.filterSchemas/filterSchema.js
import { logicalOperatorSchema } from "./logicalOperatorSchema.js";
const filterSchema = {
type: "object",
oneOf: [logicalOperatorSchema],
};
export { filterSchema };
.filterSchemas/logicalOperatorSchema.js
import { notSchema } from "./notSchema.js";
const logicalOperatorSchema = {
type: "object",
oneOf: [notSchema],
};
export { logicalOperatorSchema };
.filterSchemas/notSchema.js
import { filterSchema } from "./filterSchema.js";
const notSchema = {
type: "object",
properties: {
$not: filterSchema,
},
required: ["$not"],
additionalProperties: false,
};
export { notSchema };
Do you have any suggestions how to solve this problem?
I also tried to put all schemas into a single file but that didn't solve the actual problem.
schemas.js
const notSchema = {
type: "object",
properties: {
$not: filterSchema,
},
required: ["$not"],
additionalProperties: false,
};
const logicalOperatorSchema = {
type: "object",
oneOf: [notSchema],
};
const filterSchema = {
type: "object",
oneOf: [logicalOperatorSchema],
};
export { filterSchema }
And I also do think that solving this problem solves the other one
const foo = {
x: bar
};
const bar = {
y: foo
};
console.log(foo);
You can do it like this, but it is not going to be useful.
var foo = {
x: bar
}
var bar = {
y: foo
}
foo.x = bar
bar.y = foo
console.log(foo)
console.log(foo.x.y.x.y)
Related
I have a nested array of objects like this:
var posts = [
{
_id:1234,
body:"text",
comments:[
{
_id:234,
body:"hello world", {
]
},
{
_id:434,
body:"hello world",
replies:[
{
_id:0e2345,
body:"hello",
{
]
}
]
}
]
I want to use normalizr to simplify array and use with redux. I have read the Normalizr documentation but it has few examples and I do not know what I am doing wrong.
I have tried the following code without success. The result I get is an array with undefined.
export function getPosts(state, action) {
const { payload } = action;
const { data} = payload;
const normalized = new schema.Entity("posts", {}, { idAttribute: "_id",});
const normalizedData = normalize(data, [normalized]);
return {
...state,
normalizedData,
};
}
I need something like this:
entities:{
posts:{
123:{
_id:123,
body:"hello world",
comments:{
234:{
_id:234,
body:"hello world",
replies:{
0e2345:{
_id:0e2345,
body:"oh no"
}
}
}
}
}
}
}
I've tried to reproduce this using a JSON object:
[{
"_id":1234,
"body":"text",
"comments":[
{
"_id":234,
"body":"hello world" }
]
},
{
"_id":434,
"body":"hello world",
"replies":[
{
"_id":0e2345,
"body":"hello"
}
]
}
]
And making the structure in the code:
import data from "./data.json";
import { normalize, schema } from "normalizr";
const _id = new schema.Entity('_id');
const body = new schema.Entity('body');
const normalized = new schema.Entity("posts", {
posts:{
_id:{
_id:_id,
body:body,
comments:{
_id:{
_id:_id,
body:body,
replies:{
_id:{
_id:_id,
body:body
}
}
}
}
}
}
});
const normalizedData = normalize(data, [normalized]);
console.log(normalizedData);
I get the next console output.
we are using ngxs and we do have some lazy selectors defined in separated files from the state definition
export class SectionSelectors {
#Selector([CatalogState])
static ById(state: CatalogModel) {
return function getSectionById(id: number): Section {
const selectedSection: Section = state.sections[id];
return selectedSection;
};
}
}
And we have test cases like
import { TestBed } from '#angular/core/testing';
import { Section } from '#miq-catalog/catalog';
import { NgxsModule, Store } from '#ngxs/store';
import { CatalogModel, CatalogState } from './catalog.state';
import { SectionSelectors } from './section.selectors';
describe('SectionSelectors', () => {
it('should select the section by id', () => {
const one: Section = { sectionId: 1, title: '', columns: [] };
const two: Section = { sectionId: 2, title: '', columns: [] };
const state: CatalogModel = {
catalog: [],
sections: { 1: one, 2: two },
columns: {},
catalogLoaded: true,
};
const selectionFunction = SectionSelectors.ById(state);
const result = selectionFunction(1);
expect(result).toBeDefined();
expect(result).toBe(one);
expect(result.sectionId).toBe(1);
const result2 = selectionFunction(2);
expect(result2).toBeDefined();
expect(result2).toBe(two);
expect(result2.sectionId).toBe(2);
});
});
We are passing the state to the selector however we are getting the next error
An error was thrown in afterAll
Uncaught ReferenceError: Cannot access 'CatalogState' before initialization
ReferenceError: Cannot access 'CatalogState' before initialization
I noticed that if I move these selector to the CatalogState (where the #State definition is) the problem is fixed. But this is forcing us to put all selectors there and we think it's good to have them scoped on their own related files so we don't "pollute" with mixed selectors.
Is there a way we can fix the test case? Does someone already faced this Lazy Selector testing before?
As complementary info this is how our State looks like
#State({
name: 'Catalog',
defaults: {
catalogLoaded: false,
columns: {},
sections: {},
catalog: [],
},
})
export class CatalogState {
constructor(private store: Store) {}
#Action(RetrieveCatalogInfo)
#Action(ChangeColumnConfig)
#Action(ClearCatalog)
public executeAction(ctx: StateContext<CatalogModel>, params: ExecutableAction<CatalogModel>) {
return params.execute({ ctx, store: this.store });
}
}
This should not be a problem with the latest version of NGXS (since v3.6.1).
I'm currently trying to cover 100% of my function but I'm facing a branch not covered and it don't understand why it's not covered and even how to fix and cover it.
test coverage result here
It tried many different tests but it didn't changed anything. I don't if the problems comes from me or Jest ?
My function
export const removeProductInList = (state: IItems, action: IBasketRemoveProductAction) => {
const {
payload: { uuid },
} = action;
const { [uuid]: itemToRemove, ...restOfItems } = state;
return restOfItems;
};
My tests
product1 = { id: 1 };
product2 = { id: 2 };
mockUuid1 = 'IdTest';
mockUuid2 = 'IdTest2';
mockItem1 = { product: product1, quantity: 1 };
mockItem2 = { product: product2, quantity: 1 };
mockListItems = {
[mockUuid1]: mockItem1,
[mockUuid2]: mockItem2,
};
it('should handle PRODUCT__REMOVE', () => {
expect(removeProductInList({ [mockUuid1]: mockItem1 }, removeProduct(mockUuid1))).toEqual({});
expect(removeProductInList(mockListItems, removeProduct(mockUuid1))).toEqual({ [mockUuid2]: mockItem2 });
expect(removeProductInList({}, removeProduct('acac'))).toEqual({});
});
I expect to cover all the function with my actual test.
My version of jest is 23.4.1, just in case.
You just have to specify the target esnext in your tsConfig file in ts-jest.
// jest.config.js
module.exports = {
...
'ts-jest': {
....
tsConfig: './tsconfig.json'),
},
// tsconfig.json
{
...,
"target": "esnext",
}
Try to test the removeProductList with extra properties
expect(removeProductInList({ [mockUuid1]: mockItem1, extraProp: 'someValue' }, removeProduct(mockUuid1))).toEqual({});
In my case, I followed Nicolas' answer and edited babel.config.json as below and it worked. Thank you, Nicolas.
{
"presets": ["#babel/preset-env"],
"targets": {"esmodules": true} <-- added this line
}
I want to create a tree in VS code, but my problem is how to manually add a node to my tree. I am not sure from where to start. I tried to review all the projects that created a tree for VScode as an extension.
My problem is that I am not an expert in Typescript and the examples are not so clear or I am not sure how it is working.
Would you mind helping me to understand how to create the tree in VS code? My problem is with creating a node and then adding the node to tree.
I reviewed these projects:
vscode-code-outline
vscode-extension-samples
vscode-git-tree-compare
vscode-html-languageserver-bin
vscode-mock-debug
vscode-tree-view
Update1:
I managed to use "vscode-extension-samples" and generate the below code examples; now I don't know what I should do, or in other words, how to fill the tree. I tried to use mytree class to fill the data but it didn't work. Would you mind advising me what is next?
extension.ts
'use strict';
import * as vscode from 'vscode';
import { DepNodeProvider } from './nodeDependencies'
import { JsonOutlineProvider } from './jsonOutline'
import { FtpExplorer } from './ftpExplorer.textDocumentContentProvider'
import { FileExplorer } from './fileExplorer';
//mycode
import { SCCExplorer } from './sccExplorer';
export function activate(context: vscode.ExtensionContext) {
// Complete Tree View Sample
new FtpExplorer(context);
new FileExplorer(context);
//mycode
new SCCExplorer(context);
// Following are just data provider samples
const rootPath = vscode.workspace.rootPath;
const nodeDependenciesProvider = new DepNodeProvider(rootPath);
const jsonOutlineProvider = new JsonOutlineProvider(context);
vscode.window.registerTreeDataProvider('nodeDependencies', nodeDependenciesProvider);
vscode.commands.registerCommand('nodeDependencies.refreshEntry', () => nodeDependenciesProvider.refresh());
vscode.commands.registerCommand('nodeDependencies.addEntry', node => vscode.window.showInformationMessage('Successfully called add entry'));
vscode.commands.registerCommand('nodeDependencies.deleteEntry', node => vscode.window.showInformationMessage('Successfully called delete entry'));
vscode.commands.registerCommand('extension.openPackageOnNpm', moduleName => vscode.commands.executeCommand('vscode.open', vscode.Uri.parse(`https://www.npmjs.com/package/${moduleName}`)));
vscode.window.registerTreeDataProvider('jsonOutline', jsonOutlineProvider);
vscode.commands.registerCommand('jsonOutline.refresh', () => jsonOutlineProvider.refresh());
vscode.commands.registerCommand('jsonOutline.refreshNode', offset => jsonOutlineProvider.refresh(offset));
vscode.commands.registerCommand('jsonOutline.renameNode', offset => jsonOutlineProvider.rename(offset));
vscode.commands.registerCommand('extension.openJsonSelection', range => jsonOutlineProvider.select(range));
}
sccExplorer.ts
import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';
import * as mkdirp from 'mkdirp';
import * as rimraf from 'rimraf';
//#region Utilities
interface Entry {
uri: vscode.Uri,
type: vscode.FileType
}
//#endregion
export class FileSystemProvider implements vscode.TreeDataProvider<Entry> {
getTreeItem(element: Entry): vscode.TreeItem | Thenable<vscode.TreeItem> {
throw new Error("Method not implemented.");
}
onDidChangeTreeData?: vscode.Event<Entry>;
getChildren(element?: Entry): vscode.ProviderResult<Entry[]> {
throw new Error("Method not implemented.");
}
getParent?(element: Entry): vscode.ProviderResult<Entry> {
throw new Error("Method not implemented.");
}
private _onDidChangeFile: vscode.EventEmitter<vscode.FileChangeEvent[]>;
constructor() {
this._onDidChangeFile = new vscode.EventEmitter<vscode.FileChangeEvent[]>();
}
}
export class SCCExplorer {
private fileExplorer: vscode.TreeView<any>;
constructor(context: vscode.ExtensionContext) {
const treeDataProvider = new myTree().directories;
this.fileExplorer = vscode.window.createTreeView('scc_Explorer', { treeDataProvider });
vscode.commands.registerCommand('scc_Explorer.openFile', (resource) => this.openResource(resource));
}
private openResource(resource: vscode.Uri): void {
vscode.window.showTextDocument(resource);
}
}
export class myTree{
directories: any;
constructor()
{
this.directories = [
{
name: 'parent1',
child: [{
name: 'child1',
child: []
},
{
name: 'child2',
child: []
}]
},
{
name: 'parent2',
child: {
name: 'child1',
child: []
}
},
{
name: 'parent2',
child: [{
name: 'child1',
child: []
},
{
name: 'child2',
child: []
}]
}];
}
}
I finally got it working. It took me very long and I had it right all the time. My issue was I never did explicitly expand the items, so I would never see nested results and only the top level.
Basic working example
import * as vscode from "vscode";
export class OutlineProvider
implements vscode.TreeDataProvider<any> {
constructor(private outline: any) {
console.log(outline);
}
getTreeItem(item: any): vscode.TreeItem {
return new vscode.TreeItem(
item.label,
item.children.length > 0
? vscode.TreeItemCollapsibleState.Expanded
: vscode.TreeItemCollapsibleState.None
);
}
getChildren(element?: any): Thenable<[]> {
if (element) {
return Promise.resolve(element.children);
} else {
return Promise.resolve(this.outline);
}
}
}
export function activate(context: vscode.ExtensionContext) {
let disposable = vscode.commands.registerCommand(
"outliner.outline",
async () => {
vscode.window.registerTreeDataProvider(
"documentOutline",
new OutlineProvider([dataObject])
);
}
);
context.subscriptions.push(disposable);
}
const dataObject = {
label: "level one",
children: [
{
label: "level two a",
children: [
{
label: "level three",
children: [],
},
],
},
{
label: "level two b",
children: [],
},
],
}
And of course in package.json
"contributes": {
"commands": [
{
"command": "outliner.outline",
"title": "Outline"
}
],
"views": {
"explorer": [
{
"id": "documentOutline",
"name": "Document Outline"
}
]
}
},
Types
note the type for treeDataProvider is not neccecarly what you return. Only the getTree item has to return a tree item or a class that extends it.
interface CustomType {
label: string
children?: CustomType[]
}
export class TypeExample
implements vscode.TreeDataProvider<CustomType> {
constructor(private data: CustomType[]) { }
getTreeItem(element: CustomType): vscode.TreeItem {
return new vscode.TreeItem(
element.label,
(element.children?.length ?? 0) > 0
? vscode.TreeItemCollapsibleState.Expanded
: vscode.TreeItemCollapsibleState.None
);
}
getChildren(element?: CustomType): Thenable<CustomType[]> {
return element && Promise.resolve(element.children ?? [])
|| Promise.resolve(this.data);
}
}
I thought at first the type of the data provider should be the return type of the tree item, this doesnt make much sense of course and I was trying to wrap my head around the reasoning. Now I understand that you pass your custom type in and all other methods inherit this type and expect this type as its argument. Only the getTreeItem method has to return a valid tree item that can be rendered.
I am trying to get the following example working:
https://github.com/typeorm/javascript-example/tree/master/src/app3-es6
I am running into the following error:
Error
at new RepositoryNotFoundError (...\node_modules\typeorm\connection\error\RepositoryNotFoundError.js:24:23)
at Connection.findRepositoryAggregator (...\node_modules\typeorm\connection\Connection.js:513:19)
at Connection.getRepository (...\node_modules\typeorm\connection\Connection.js:405:21)
at ...\index.js:27:37
name: 'RepositoryNotFoundError',
message: 'No repository for "Post" was found. Looks like this entity is not registered in current "default" connection?'
here is index.js
const typeorm = require("typeorm"); // import * as typeorm from "typeorm";
const Post = require("./model/Post"); // import {Post} from "./model/Post";
// import Post from './model/Post.js';
const Category = require("./model/Category"); // import {Category} from "./model/Category";
typeorm.createConnection({
driver: {
type: "oracle",
host: "localhost",
port: 1521,
username: "uname",
password: "pwd",
sid: "dev"
},
entities: [
__dirname + "/entity/*.js"
],
autoSchemaSync: true
}).then(function (connection) {
console.log(connection);
let post = new Post.Post();
post.title = "Control flow based type analysis";
post.text = "TypeScript 2.0 implements a control flow-based type analysis for local variables and parameters.";
post.categories = [new Category.Category(0, "TypeScript"), new Category.Category(0, "Programming")];
let postRepository = connection.getRepository(Post.Post);
postRepository.persist(post)
.then(function(savedPost) {
console.log("Post has been saved: ", savedPost);
console.log("Now lets load all posts: ");
return postRepository.find();
})
.then(function(allPosts) {
console.log("All posts: ", allPosts);
});
}).catch(function(error) {
console.log("Error: ", error);
});
Post.js in /model/
/*export */ class Post {
constructor(id, title, text, categories) {
this.id = id;
this.title = title;
this.text = text;
this.categories = categories;
}
}
module.exports = {
Post: Post
};
Category.js
/*export */ class Category {
constructor(id, name) {
this.id = id;
this.name = name;
}
}
module.exports = {
Category: Category
};
PostSchema.js in /entity/
const Post = require("../model/Post"); // import {Post} from "../model/Post";
const Category = require("../model/Category"); // import {Category} from "../model/Category";
const PostSchema = {
target: Post,
columns: {
id: {
primary: true,
type: "int",
generated: true
},
title: {
type: "string"
},
text: {
type: "text"
}
},
relations: {
categories: {
target: Category,
type: "many-to-many",
joinTable: true,
cascadeInsert: true
}
}
};
module.exports = {
PostSchema: PostSchema
};
CategorySchema.js
const Category = require("../model/Category"); // import {Category} from "../model/Category";
const CategorySchema = {
target: Category,
columns: {
id: {
primary: true,
type: "int",
generated: true
},
name: {
type: "string"
}
}
};
module.exports = {
CategorySchema: CategorySchema
};
i dont know what i am doing wrong
It looks like your entity import is not working. If you import via the wildcard:
entities: [
__dirname + "/entity/*.js"
],`
Make sure your model is compiled to js. You also could just import
createConnection({
...,
entities: [
Post,
...
],}).then(...)
For those who are using typescript and experience this problem: Be reminded that you need to include both ts and js file suffixes when specifying the entities-path:
ts used when locally running with ts-node
js used when having
built for production via tsc.
Code:
import * as path from 'path';
// ...
entities: [
// assuming _dirname is your project root
path.resolve(__dirname, '**/*.entity{.ts,.js}'),
],
I had the same problem for months and finally figured out what I was doing wrong.
When you import Entities, make sure the file names are EXACTLY matching. It's not going to throw any errors, but during the run time, it's going to throw the above error.
Ex. In the entity or model classes, if we import like this,
import { FooClass } from "./foo-Class.model";
it's different from
import { FooClass } from "./foo-class.model";
It won't show any errors, but when you try to call the table, it will show the exact same error.
I had the same problem. None of the solutions worked for me. After much debugging I figured out that you'll receive this error if your connection is closed.
So if you are facing this error, make sure your connection is not closed.
try {
connection = getConnection(config.name)
//after adding this if block, I no longer received this error
if (!connection.isConnected) {
await connection.connect();
}
} catch(err) {
connection = await createConnection(config);
}
If it is closed, connect it again.