quick-erd
Advanced tools
+18
-3
@@ -31,2 +31,3 @@ import { Position } from './meta'; | ||
| parseField(): Field; | ||
| parseFieldModifiers(field: Field): void; | ||
| skipLine(line?: string): void; | ||
@@ -36,5 +37,5 @@ parseEmptyLine(): void; | ||
| parseType(): string | undefined; | ||
| parseDefaultValue(): string; | ||
| parseDefaultValue(field: Field): string; | ||
| parseRelationType(): RelationType; | ||
| parseForeignKeyReference(ref_field_name: string): ForeignKeyReference; | ||
| parseForeignKeyReference(field: Field): ForeignKeyReference; | ||
| } | ||
@@ -75,4 +76,18 @@ export type Table = { | ||
| }; | ||
| /** | ||
| | Relation Type | Description | | ||
| | ---- | ----------- | | ||
| | - | one TO one | | ||
| | -< | one TO many | | ||
| | >- | many TO one | | ||
| | >-< | many TO many | | ||
| | -0 | one TO zero or one | | ||
| | 0- | zero or one TO one | | ||
| | 0-0 | zero or one TO zero or one | | ||
| | -0< | one TO zero or many | | ||
| | >0- | zero or many TO one | | ||
| */ | ||
| type: RelationType; | ||
| }; | ||
| export type RelationType = '|' | '-<' | '>-' | '>-<' | '-0' | '0-' | '0-0' | '-0<' | '>0-'; | ||
| export type RelationType = (typeof RelationTypes)[number]; | ||
| export declare const RelationTypes: ("-" | ">0-" | "-0<" | ">-<" | "0-0" | ">-" | "-<" | "0-" | "-0")[]; |
+125
-59
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.Parser = void 0; | ||
| exports.RelationTypes = exports.Parser = void 0; | ||
| exports.parse = parse; | ||
@@ -25,7 +25,3 @@ const enum_1 = require("./enum"); | ||
| input.split('\n').forEach(line => { | ||
| line = line | ||
| .trim() | ||
| .replace(/#.*/, '') | ||
| .replace(/\/\/.*/, '') | ||
| .trim(); | ||
| line = stripComments(line); | ||
| if (!line) | ||
@@ -110,59 +106,76 @@ return; | ||
| parseField() { | ||
| const field_name = this.parseName(); | ||
| let type = ''; | ||
| let is_null = false; | ||
| let is_unique = false; | ||
| let is_primary_key = false; | ||
| let is_unsigned = false; | ||
| let default_value; | ||
| let references; | ||
| const field = { | ||
| name: this.parseName(), | ||
| type: '', | ||
| is_null: false, | ||
| is_unique: false, | ||
| is_primary_key: false, | ||
| is_unsigned: false, | ||
| default_value: undefined, | ||
| references: undefined, | ||
| }; | ||
| for (;;) { | ||
| const name = this.parseType(); | ||
| if (!name) | ||
| this.parseFieldModifiers(field); | ||
| const token = this.parseType(); | ||
| if (!token) | ||
| break; | ||
| switch (name.toUpperCase()) { | ||
| case 'NULL': | ||
| is_null = true; | ||
| continue; | ||
| case 'UNIQUE': | ||
| is_unique = true; | ||
| continue; | ||
| case 'UNSIGNED': | ||
| is_unsigned = true; | ||
| continue; | ||
| switch (token.toUpperCase()) { | ||
| case 'DEFAULT': | ||
| // TODO parse default value | ||
| default_value = this.parseDefaultValue(); | ||
| field.default_value = this.parseDefaultValue(field); | ||
| continue; | ||
| case 'PK': | ||
| is_primary_key = true; | ||
| continue; | ||
| case 'FK': | ||
| references = this.parseForeignKeyReference(field_name); | ||
| field.references = this.parseForeignKeyReference(field); | ||
| continue; | ||
| default: | ||
| if (type) { | ||
| if (field.type) { | ||
| console.debug('unexpected token:', { | ||
| field_name, | ||
| type, | ||
| token: name, | ||
| field_name: field.name, | ||
| type: field.type, | ||
| token: token, | ||
| }); | ||
| continue; | ||
| } | ||
| type = name; | ||
| field.type = token; | ||
| } | ||
| } | ||
| type ||= defaultFieldType; | ||
| field.type ||= defaultFieldType; | ||
| this.skipLine(); | ||
| return { | ||
| name: field_name, | ||
| type, | ||
| is_null, | ||
| is_unique, | ||
| is_primary_key, | ||
| is_unsigned, | ||
| default_value, | ||
| references, | ||
| }; | ||
| return field; | ||
| } | ||
| parseFieldModifiers(field) { | ||
| let line = this.peekLine(); | ||
| loop: for (;;) { | ||
| let match = line.match(/^not null\s*/i); | ||
| if (match) { | ||
| field.is_null = false; | ||
| line = line.slice(match[0].length); | ||
| continue; | ||
| } | ||
| match = line.match(/^\w+/); | ||
| if (!match) | ||
| break; | ||
| const token = match[0]; | ||
| switch (token.toUpperCase()) { | ||
| case 'NULL': | ||
| field.is_null = true; | ||
| break; | ||
| case 'UNIQUE': | ||
| field.is_unique = true; | ||
| break; | ||
| case 'UNSIGNED': | ||
| field.is_unsigned = true; | ||
| break; | ||
| case 'PK': | ||
| field.is_primary_key = true; | ||
| break; | ||
| default: | ||
| // no single token modifier | ||
| break loop; | ||
| } | ||
| line = line.replace(token, '').trim(); | ||
| break; | ||
| } | ||
| this.line_list[0] = line; | ||
| } | ||
| skipLine(line = '') { | ||
@@ -209,3 +222,4 @@ if (this.line_list[0]?.startsWith(line)) { | ||
| } | ||
| parseDefaultValue() { | ||
| parseDefaultValue(field) { | ||
| this.parseFieldModifiers(field); | ||
| let line = this.peekLine(); | ||
@@ -235,12 +249,19 @@ let end; | ||
| let line = this.peekLine(); | ||
| const match = line.match(/.* /); | ||
| if (!match) { | ||
| for (const type of exports.RelationTypes) { | ||
| if (line.startsWith(type)) { | ||
| line = line.slice(type.length).trim(); | ||
| this.line_list[0] = line; | ||
| return type; | ||
| } | ||
| } | ||
| line = line.trim(); | ||
| let match = line.match(/^\w+/); | ||
| if (line && !match) { | ||
| throw new ParseRelationTypeError(line); | ||
| } | ||
| const type = match[0].trim(); | ||
| line = line.replace(match[0], '').trim(); | ||
| this.line_list[0] = line; | ||
| return type; | ||
| return defaultRelationType; | ||
| } | ||
| parseForeignKeyReference(ref_field_name) { | ||
| parseForeignKeyReference(field) { | ||
| let ref_field_name = field.name; | ||
| this.parseFieldModifiers(field); | ||
| if (ref_field_name.endsWith('_id') && this.peekLine() === '') { | ||
@@ -253,12 +274,15 @@ return { | ||
| } | ||
| this.parseFieldModifiers(field); | ||
| const type = this.parseRelationType(); | ||
| this.parseFieldModifiers(field); | ||
| const table = this.parseName(); | ||
| this.parseFieldModifiers(field); | ||
| const line = this.peekLine(); | ||
| let field; | ||
| let field_name; | ||
| if (line == '') { | ||
| field = 'id'; | ||
| field_name = 'id'; | ||
| } | ||
| else if (line.startsWith('.')) { | ||
| this.line_list[0] = line.slice(1); | ||
| field = this.parseName(); | ||
| field_name = this.parseName(); | ||
| } | ||
@@ -268,3 +292,3 @@ else { | ||
| } | ||
| return { type, table, field }; | ||
| return { type, table, field: field_name }; | ||
| } | ||
@@ -304,3 +328,45 @@ } | ||
| } | ||
| function stripComments(line) { | ||
| // check for enum with comment symbols | ||
| let match = line.match(/(enum\(.*?\))/i); | ||
| if (match) { | ||
| let parts = line.split(match[0]); | ||
| let before = parts[0]; | ||
| let strippedBefore = stripComments(before); | ||
| if (strippedBefore !== before.trim()) { | ||
| return strippedBefore; | ||
| } | ||
| let enumStr = match[0]; | ||
| let after = parts.slice(1).join(enumStr); | ||
| return before + enumStr + stripComments(after); | ||
| } | ||
| line = line | ||
| .trim() | ||
| // strip `#` comments | ||
| .replace(/#.*/, '') | ||
| // strip `//` comments | ||
| .replace(/\/\/.*/, '') | ||
| .trim(); | ||
| // if line is only dashes, keep it as delimiter after table name, otherwise strip it as comment | ||
| if (!line.match(/^-+$/)) { | ||
| // strip `--` comments | ||
| line = line.replace(/--.*/, '').trim(); | ||
| } | ||
| return line; | ||
| } | ||
| exports.RelationTypes = [ | ||
| // 3 chars tokens first | ||
| '>0-', | ||
| '-0<', | ||
| '>-<', | ||
| '0-0', | ||
| // then 2 chars tokens | ||
| '>-', | ||
| '-<', | ||
| '0-', | ||
| '-0', | ||
| // finally 1 char tokens | ||
| '-', | ||
| ]; | ||
| const defaultFieldType = 'integer'; | ||
| const defaultRelationType = '>0-'; |
+3
-3
| { | ||
| "name": "quick-erd", | ||
| "version": "4.29.1", | ||
| "version": "4.30.0", | ||
| "type": "commonjs", | ||
@@ -104,3 +104,3 @@ "sideEffects": false, | ||
| "knex": "^2 || ^3", | ||
| "mocha": "^10.8.2", | ||
| "mocha": "^8.4.0", | ||
| "npm-run-all": "^4.1.5", | ||
@@ -115,3 +115,3 @@ "nyc": "^17.1.0", | ||
| "surge": "^0.24.6", | ||
| "ts-mocha": "^10.1.0", | ||
| "ts-mocha": "^8.0.0", | ||
| "ts-node": "^10.9.2", | ||
@@ -118,0 +118,0 @@ "ts-node-dev": "^2.0.0", |
Sorry, the diff of this file is too big to display
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
287540
1.6%7889
1.81%