Created
February 6, 2017 04:52
-
-
Save tomitrescak/75d9f158c48124431b3a3b989bb93f02 to your computer and use it in GitHub Desktop.
ts issue
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface IFileOwner { | |
files: App.Collections.ITextFileDAO[]; | |
} | |
export const ClassUtils = { | |
alphanumSort<T>(array: Array<T>, selector?: (obj: T) => string, sensitivity = 'base') { | |
return array.sort((a, b) => selector(a).localeCompare(selector(b), undefined, {numeric: true, sensitivity})); | |
}, | |
indexArray(arr: any[]): any[] { | |
if (arr.length === 0) { | |
return arr; | |
} | |
if (typeof arr[0] === 'string') { | |
let arr1 = <any>[]; | |
for (let i = 0; i < arr.length; i++) { | |
arr1.push({ value: arr[i], index: i, nextIndex: i + 1 }); | |
} | |
return arr1; | |
} else { | |
for (let i = 0; i < arr.length; i++) { | |
arr[i].index = i; | |
arr[i].nextIndex = i + 1; | |
} | |
} | |
return arr; | |
}, | |
find<T>(obj: Object, callback: (elem: T) => boolean): T { | |
let props = Object.getOwnPropertyNames(obj); | |
for (let prop of props) { | |
if (callback(obj[prop])) { | |
return obj[prop]; | |
} | |
} | |
return null; | |
}, | |
/** | |
* Removes all comments from the code | |
* | |
* @param {string} code | |
* @returns {string} | |
*/ | |
stripCode(code: string): string { | |
let formattedCode = ''; | |
// remove strings | |
let sq = false, dq = false; | |
for (let c = 0; c < code.length; c++) { | |
if (code[c] === '\"' && code[c - 1] !== '\\') { dq = !sq && !dq; formattedCode += code[c]; continue; } | |
if (code[c] === "'" && code[c - 1] !== '\\') { sq = !dq && !sq; formattedCode += code[c]; continue; } | |
if (!dq && !sq) { | |
formattedCode += code[c]; | |
} | |
} | |
// remove multi line comments | |
formattedCode = formattedCode.replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\//g, ''); | |
// remove single line comments | |
formattedCode = formattedCode.replace(/\/\/.*/g, ''); | |
return formattedCode; | |
}, | |
getLinesOfCodeInFiles(files: App.Entities.TextFile[]): App.Shared.ILocInfo { | |
let locInfo: App.Shared.ILocInfo = { loc: 0 }; | |
for (let f of files) { | |
locInfo.loc += ClassUtils.getLinesOfCode(f.source).loc; | |
} | |
return locInfo; | |
}, | |
getLinesOfCode(code: string): App.Shared.ILocInfo { | |
let locInfo: App.Shared.ILocInfo = {}; | |
locInfo.loc = 0; | |
if (code === null) { | |
return locInfo; | |
} | |
const formattedCode = ClassUtils.stripCode(code); | |
let loc = 0; | |
// count functions | |
let fcReg = /(String|boolean|int|double|float|void|function)( +([\w_]+) *\()/g; | |
let fcMatches: RegExpExecArray = null; | |
locInfo.functions = 0; | |
while ((fcMatches = fcReg.exec(formattedCode)) !== null) { | |
locInfo.functions++; | |
const name = fcMatches[3]; | |
let fcUseReg = new RegExp(name + ' *\\(', 'g'); | |
if (formattedCode.match(fcUseReg).length > 1) { loc -= 1; }; | |
} | |
// count semicolons | |
let matches = formattedCode.match(/;/g); | |
if (matches !== null) { | |
loc += matches.length; | |
locInfo.commands = matches.length; | |
} | |
// match all ifs | |
matches = formattedCode.match(/if\W*\(/g); | |
if (matches !== null) { | |
loc += matches.length; | |
locInfo.ifs = matches.length; | |
} | |
// match all elses | |
matches = formattedCode.match(/else\W*/g); | |
if (matches !== null) { | |
loc += matches.length; | |
locInfo.elses = matches.length; | |
} | |
// deduct all else ifs | |
matches = formattedCode.match(/else\W+if\W*\(/g); | |
if (matches !== null) { | |
loc -= matches.length; | |
locInfo.elseIfs = matches.length; | |
} | |
// match all whiles | |
matches = formattedCode.match(/while\W*\(/g); | |
if (matches !== null) { | |
loc += matches.length; | |
locInfo.whiles = matches.length; | |
} | |
// match all dos | |
matches = formattedCode.match(/do\W*\{/g); | |
if (matches !== null) { | |
loc += matches.length; | |
locInfo.dos = matches.length; | |
} | |
// match all fors (we put minus, since each for has two semicolons) | |
matches = formattedCode.match(/for\W*\(/g); | |
if (matches !== null) { | |
locInfo.fors = matches.length; | |
} | |
// match all fors (we put minus, since each for has two semicolons) | |
matches = formattedCode.match(/\bcase\b/g); | |
if (matches !== null) { | |
loc += matches.length; | |
locInfo.cases = matches.length; | |
} | |
// match all fors (we put minus, since each for has two semicolons) | |
matches = formattedCode.match(/\bswitch\b/g); | |
if (matches !== null) { | |
loc += matches.length; | |
locInfo.switches = matches.length; | |
} | |
// match all logical expressions | |
matches = formattedCode.match(/(\|\||\&\&)/g); | |
if (matches !== null) { | |
locInfo.logicals = matches.length; | |
loc += matches.length; | |
} | |
locInfo.loc = loc; | |
return locInfo; | |
}, | |
createFormObject(obj: any) { | |
const result = {} as any; | |
const keys = Object.getOwnPropertyNames(obj); | |
// prepare owner | |
for (let key of keys) { | |
let owner = result; | |
const parts = key.split('.'); | |
for (let i = 0; i < parts.length - 1; i++) { | |
const part = parts[i]; | |
const isArray = Number.isInteger(parseInt(parts[i + 1], 10)); | |
// if owner does not have this part | |
if (!owner[part]) { | |
// if next part is integer we will create an array | |
if (isArray) { | |
let newOwner = [] as any; | |
owner[part] = newOwner; | |
owner = newOwner; | |
} else { | |
let newOwner = {}; | |
owner[part] = newOwner; | |
owner = newOwner; | |
} | |
} else { | |
owner = owner[part]; | |
} | |
} | |
const lastKey = parts[parts.length - 1]; | |
const isArray = Number.isInteger(parseInt(lastKey, 10)); | |
if (isArray) { | |
owner.push(obj[key]); | |
} else { | |
owner[lastKey] = obj[key]; | |
} | |
} | |
return result; | |
}, | |
mergeFiles(owners: IFileOwner[], keepCopies = false) { | |
let files: App.Collections.ITextFileDAO[] = []; | |
let ownerIndex = 0; | |
owners = owners.reverse(); | |
for (let owner of owners) { | |
if (!owner || !owner.files) { | |
continue; | |
} | |
for (let file of owner.files.reverse()) { | |
// find and push or replace the element | |
const index = files.findIndex((f) => f.name === file.name); | |
if (index === -1) { | |
files.unshift(file); | |
} else { | |
if (keepCopies && !files[index].copyOf) { | |
files[index].copyOf = file; | |
} | |
} | |
// for all non-owner files we mark them readonly | |
if (ownerIndex > 0) { | |
file.readonly = true; | |
} | |
} | |
ownerIndex ++; | |
} | |
return files; | |
} | |
}; | |
// extending prototype | |
String.prototype.toUrlName = function (this: string) { | |
let result = this.replace(/\:/g, ''); | |
result = result.replace(/ - /g, '-'); | |
result = result.replace(/\W/g, '-'); | |
do { | |
result = result.replace(/--/g, '-'); | |
} while (result.indexOf('--') >= 0); | |
return result.toLowerCase(); | |
}; | |
String.prototype['safeFilePath'] = function (this: string) { | |
return this.replace(/\.\./g, ''); | |
}; | |
export default ClassUtils; | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Config from './config'; | |
import React from 'react'; | |
import Utils from './utils'; | |
import getState from './state'; | |
// import * as Caches from './caches'; | |
// import { query, mutation } from 'apollo-mantra'; | |
// import { mutationWithFeedback, addInsertData, addModificationData } from '../helpers/apollo_helpers'; | |
// const Apollo = { | |
// query, | |
// mutation, | |
// mutationWithFeedback, | |
// addModificationData, | |
// addInsertData | |
// }; | |
let context: App.Context; | |
let state = getState(); | |
export function initContext(forceInit = false, user?: App.User) { | |
if (!context || forceInit) { | |
context = { | |
state: getState(forceInit, user), | |
// mobxStores: { | |
// auth: state.accounts | |
// }, | |
Utils, | |
Config | |
}; | |
} | |
return context; | |
} | |
// context provider | |
interface Props { | |
context?: App.Context; | |
} | |
export class ContextProvider extends React.Component<Props, {}> { | |
getChildContext() { | |
return this.props.context || initContext(); | |
} | |
render(): any { | |
return this.props.children; | |
} | |
} | |
export const contextTypes = { | |
state: React.PropTypes.object, | |
auth: React.PropTypes.object, | |
Utils: React.PropTypes.object, | |
Config: React.PropTypes.object, | |
Binder: React.PropTypes.object, | |
client: React.PropTypes.object, | |
store: React.PropTypes.any, | |
router: React.PropTypes.any | |
}; | |
ContextProvider['childContextTypes'] = contextTypes; | |
// export const ContextProvider = ({ children }: any) => ( | |
// <Provider state={state} auth={state.accounts} Utils={Utils} Config={Config}> | |
// { children } | |
// </Provider> | |
// ); | |
// global type definitions | |
declare global { | |
namespace App { | |
export interface Dictionary<V> { | |
[key: string]: V; | |
} | |
export interface Context { | |
state: typeof state; | |
// mobxStores: { | |
// auth: typeof state.accounts; | |
// }; | |
Utils: typeof Utils; | |
Config: typeof Config; | |
client?: any; | |
store?: any; | |
router?: any; | |
} | |
} | |
} | |
export default initContext; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { observable } from 'mobx'; | |
import User, { profileData } from '../modules/user/models/user_model'; | |
import { AccountState, initState } from 'apollo-authentication-semantic-ui'; | |
import modalState from '../modules/core/actions/modal_state'; | |
import Configuration from '../modules/configuration/models/configuration_model'; | |
import File from '../modules/text_editor/models/text_file_model'; | |
import Schedule from '../modules/schedules/models/schedule_model'; | |
import Practical from '../modules/practicals/models/practical_model'; | |
import Exercise from '../modules/exercises/models/exercise_model'; | |
import Marking from '../modules/marking/models/marking_model'; | |
import Solution from '../modules/exercises/models/solution_model'; | |
import Organisation from '../modules/organisations/models/organisation_model'; | |
import World from '../modules/worlds/models/world_model'; | |
import Debugger from '../modules/debugger/models/debugger_model'; | |
import TextFile from '../modules/text_editor/models/text_file_model'; | |
import { Profile } from '../modules/user/models/profile_state_model'; | |
import ClassHelpers from '../../shared/helpers/class_helpers'; | |
import { RouterUtils } from '../helpers/helpers_client'; | |
// import scheduleReducer, { IScheduleState } from '../modules/schedules/actions/schedule_reducer'; | |
// import practicalReducer, { IPracticalState } from '../modules/practicals/actions/practical_reducer'; | |
// import exerciseReducer, { ExerciseState } from '../modules/exercises/actions/exercise_reducer'; | |
// import solutionReducer, { ISolutionState } from '../modules/exercises/actions/solution_reducer'; | |
import compilerState from '../modules/exercises/models/compiler_state'; | |
// import worldReducer, { IWorldState } from '../modules/worlds/actions/worlds_reducer'; | |
import editorState from '../modules/text_editor/models/text_editor_state'; | |
// import boardReducer, { IBoardState } from '../modules/board/actions/board_reducer'; | |
// import debuggerReducer, { IDebuggerState } from '../modules/debugger/actions/debugger_reducer'; | |
class StateModel implements App.State { | |
@observable activeOrganisation = 'public'; | |
@observable saving = false; | |
@observable activeTool = 'edit'; | |
accounts: AccountState<App.User>; | |
compiler = compilerState; | |
editor = editorState; | |
modal = modalState; | |
@observable feedbackSubmitted = false; | |
schedules = {}; | |
practicals = {}; | |
exercises = {}; | |
exerciseEntities = {}; | |
solutions = {}; | |
boardEditors = {}; | |
worlds = {}; | |
debuggers = {}; | |
marking = {}; | |
organisations = {}; | |
configuration: App.Models.Configuration = null; | |
profile: Profile = null; | |
constructor(user?: App.User) { | |
this.activeOrganisation = user ? user.profile.organisations[0] : 'public'; | |
const state = new AccountState((data: any) => new User(data, this.login.bind(this), this.logout.bind(this)), profileData, user); | |
this.accounts = state; | |
initState(state); | |
} | |
login(data: App.User) { | |
this.activeOrganisation = data.profile.organisations[0]; | |
} | |
logout() { | |
this.activeOrganisation = 'public'; | |
this.profile = null; | |
RouterUtils.go('/'); | |
} | |
getModel(id: string, collection: Object, data: any, Model: any) { | |
let model = collection[id]; | |
if (!model && data && data._id === id) { | |
model = new Model(data); | |
collection[id] = model; | |
} | |
return model; | |
} | |
getConfiguration(data: App.Entities.Configuration) { | |
if (this.configuration === null) { | |
this.configuration = new Configuration(data); | |
} | |
return this.configuration; | |
} | |
getEntity(id: string, collection: Object, data: any) { | |
let model = collection[id]; | |
if (!model && data) { | |
collection[id] = model; | |
} | |
return model; | |
} | |
getModelWithContructor(id: string, collection: Object, data: any, ctor: Function) { | |
let model = collection[id]; | |
if (!model && data) { | |
model = ctor(); | |
collection[id] = model; | |
} | |
return model; | |
} | |
getSchedule(id: string, data: any): Schedule { | |
return this.getModel(id, this.schedules, data, Schedule); | |
} | |
getPractical(id: string, data: any): Practical { | |
return this.getModel(id, this.practicals, data, Practical); | |
} | |
getExercise(id: string, world: App.Models.World, data: App.Entities.Exercise): Exercise { | |
let exercise = this.exercises[id]; | |
if (!exercise && data) { | |
// we need to init files in case we are creating a fresh version | |
exercise = data; | |
const tempExercise = { | |
files: data.files ? data.files.map(s => new TextFile(s)) : [] | |
}; | |
const mergedFiles = ClassHelpers.mergeFiles([world, tempExercise], true).map(f => new File(f)); | |
const newExercise = Object.assign({}, data, { files: mergedFiles }); | |
exercise = new Exercise(world, newExercise); | |
this.exercises[id] = exercise; | |
} | |
return exercise; | |
} | |
getExerciseEntity(id: string, data?: any): Practical { | |
return this.getEntity(id, this.exerciseEntities, data); | |
} | |
getOrganisation(id: string, data: any): App.Models.Organisation { | |
return this.getModel(id, this.organisations, data, Organisation); | |
} | |
getDebugger(id: string) { | |
if (!this.solutions[id]) { | |
throw new Error('Solution does not exist!: ' + id); | |
} | |
if (!this.debuggers[id]) { | |
this.debuggers[id] = new Debugger(this.solutions[id], this.compiler.getCompiler(id), this.editor.getEditor(id)); | |
} | |
return this.debuggers[id]; | |
} | |
hasSolution(id: string): boolean { | |
return this.solutions[id] != null; | |
} | |
getSolution(id: string, data?: any, schedule?: App.Entities.Schedule, practical?: App.Entities.Practical, exercise?: App.Entities.Exercise, world?: App.Models.World): Solution { | |
let solution = this.solutions[id]; | |
if (!solution && data) { | |
solution = new Solution(data); | |
solution.init(schedule, practical, exercise, world); | |
this.solutions[id] = solution; | |
// init files, we need to init TextFile objects as original objects are not extensible | |
const tempExercise = { | |
files: exercise.files ? exercise.files.map(s => new TextFile(s)) : [] | |
}; | |
const tempSolution = { | |
files: solution.files ? solution.files.map(s => new TextFile(s)) : [] | |
}; | |
const mergedFiles = ClassHelpers.mergeFiles([world, tempExercise, tempSolution]).map(f => new File(f)); | |
solution.files = observable(mergedFiles); | |
} | |
return solution; | |
} | |
getWorld(id: string, data?: any): World { | |
return this.getModel(id, this.worlds, data, World); | |
} | |
getWorlds(worlds: App.Entities.World[]): { [index: string]: World } { | |
if (Object.keys(this.worlds).length === 0) { | |
worlds.forEach(w => this.worlds[w._id] = new World(w)); | |
}; | |
return this.worlds; | |
} | |
getMarkingState(id: string): Marking { | |
if (!this.marking[id]) { | |
this.marking[id] = new Marking(); | |
} | |
return this.marking[id]; | |
} | |
getProfile() { | |
if (!this.accounts.userId) { | |
this.profile = null; | |
return null; | |
} | |
if (!this.profile) { | |
this.profile = new Profile(this.accounts.user); | |
} | |
return this.profile; | |
} | |
} | |
declare global { | |
namespace App { | |
type State = StateModel; | |
} | |
} | |
let state: StateModel; | |
export default function initAppState(forceInit = false, user?: App.User): App.State { | |
if (!state || forceInit) { | |
state = new StateModel(user); | |
global['__state'] = state; | |
} | |
return state; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment