SystemOrganization addCategory: #ExtJsBuilder! Refactoring subclass: #EJClassBuilder instanceVariableNames: 'directory category' classVariableNames: 'Matcher CommentCleaner' poolDictionaries: '' category: 'ExtJsBuilder'! !EJClassBuilder class methodsFor: 'initialization' stamp: 'lr 11/26/2007 20:41'! build self new directory: (FileDirectory on: '/Users/lukas/Desktop/ext-2.0-rc1/source'); execute! ! !EJClassBuilder class methodsFor: 'initialization' stamp: 'lr 11/27/2007 14:33'! initialize Matcher := Dictionary new. Matcher at: #initClass: put: '@class\s+((\w+\.)*)(\w+)' asRegex; at: #initConfig: put: '@cfg\s+{([^}]+)}\s+(\w+)\s*(.*)' asRegex; at: #initConstructor: put: '@constructor' asRegex; at: #initDeprecated: put: '@deprecated' asRegex; at: #initEvent: put: '@event\s+(\w+)' asRegex; at: #initMethod: put: '@method' asRegex; at: #initParam: put: '@param\s+{([^}]*)}\s*(.*)' asRegex; at: #initPrivate: put: '@private' asRegex; at: #initProperty: put: '@property' asRegex; at: #initReturn: put: '@return\s+{([^}]*)}\s*(.*)' asRegex; at: #initSingleton: put: '@singleton' asRegex; at: #initStatic: put: '@static' asRegex; at: #initExtends: put: '@extends\s+((\w+\.)*)(\w+)' asRegex; at: #initReturn: put: '@return\s+(.*)' asRegex. CommentCleaner := '@hide' asRegex! ! !EJClassBuilder methodsFor: 'accessing' stamp: 'lr 11/25/2007 11:48'! directory ^ directory! ! !EJClassBuilder methodsFor: 'accessing' stamp: 'lr 11/25/2007 11:47'! directory: aDirectory directory := aDirectory! ! !EJClassBuilder methodsFor: 'preconditions' stamp: 'lr 11/26/2007 20:43'! preconditions ^ RBCondition withBlock: [ self directory notNil and: [ self directory exists ] ] errorString: 'Directory ' , self directory printString , ' does not exist.'! ! !EJClassBuilder methodsFor: 'processing' stamp: 'lr 11/27/2007 16:02'! processClass: aDefinition members: aCollection | class | self model defineClass: ('<1s> subclass: #<2p> instanceVariableNames: '''' classVariableNames: '''' poolDictionaries: '''' category: <3p>' expandMacrosWith: aDefinition smalltalkSuperName with: aDefinition smalltalkClassName with: 'ExtJsLibrary-' , aDefinition fileCategory). class := self model classNamed: aDefinition smalltalkClassName asSymbol. class compile: ('defaultPrototype^ <1p>' expandMacrosWith: aDefinition javascriptClassName) classified: #private. class compile: ('isSingleton^ <1p>' expandMacrosWith: aDefinition isSingleton) classified: #private. aCollection do: [ :each | each isConfig ifTrue: [ class compile: ('<1s>: a<2s>"<3s>"self optionAt: <1p> put: a<2s>' expandMacrosWith: each configName with: each configType with: each comment) classified: #options ] ifFalse: [ each isEvent ifTrue: [ class compile: ('<1s>: anObject"<3s>"self optionAt: <2p> put: anObject asFunction' expandMacrosWith: each smalltalkEventName with: each javascriptEventName with: each comment) classified: #events ] ] ]! ! !EJClassBuilder methodsFor: 'processing' stamp: 'lr 11/27/2007 08:41'! processDefinitions: aCollection | class group | [ aCollection isEmpty or: [ aCollection first isClass ] ] whileFalse: [ aCollection removeFirst ]. [ aCollection isEmpty ] whileFalse: [ class := aCollection removeFirst. group := OrderedCollection new. [ aCollection isEmpty or: [ aCollection first isClass ] ] whileFalse: [ group add: aCollection removeFirst ]. self processClass: class members: group ]! ! !EJClassBuilder methodsFor: 'processing' stamp: 'lr 11/26/2007 20:58'! processFile: aString "Process the file aString." FileStream oldFileNamed: aString do: [ :stream | self processFile: aString stream: stream ]! ! !EJClassBuilder methodsFor: 'processing' stamp: 'lr 11/27/2007 08:25'! processFile: aString document: aStream "Normalize the comment in aStream and produce some lines of documentation." | lines | lines := OrderedCollection new. [ aStream atEnd ] whileFalse: [ (CommentMatcher searchStream: aStream) ifTrue: [ lines add: (CommentMatcher subexpression: 2) ] ]. ^ lines isEmpty ifFalse: [ self processFile: aString entry: lines ]! ! !EJClassBuilder methodsFor: 'processing' stamp: 'lr 11/27/2007 11:12'! processFile: aString entry: aCollection "Parse aCollection to an object representing a doc-string." | definition line found | definition := EJClassDefinition new initFileName: aString. [ aCollection isEmpty or: [ definition isNil ] ] whileFalse: [ found := false. line := aCollection removeFirst. Matcher keysAndValuesDo: [ :selector :matcher | (found not and: [ matcher search: line ]) ifTrue: [ definition := definition perform: selector with: matcher. found := true ] ]. found ifFalse: [ definition initUnknown: line ] ]. ^ definition! ! !EJClassBuilder methodsFor: 'processing' stamp: 'lr 11/27/2007 08:27'! processFile: aString stream: aStream "Find all the document comments in the given file." | definitions defintion | definitions := OrderedCollection new. [ aStream atEnd ] whileFalse: [ aStream upToAll: '/**'. aStream atEnd ifFalse: [ defintion := self processFile: aString document: (aStream upToAll: '*/') readStream. defintion isNil ifFalse: [ definitions add: defintion ] ] ]. definitions isEmpty ifFalse: [ self processDefinitions: definitions ]! ! !EJClassBuilder methodsFor: 'transforming' stamp: 'lr 11/27/2007 08:58'! transform | files | files := OrderedCollection new. self directory withAllSubdirectoriesCollect: [ :each | each fileNames do: [ :name | (name endsWith: '.js') ifTrue: [ files add: (each fullNameFor: name) ] ] ]. files do: [ :each | self processFile: each ] displayingProgress: 'Parsing'! ! Object subclass: #EJClassDefinition instanceVariableNames: 'filePath classSpace className superSpace superName comment configType configName singleton eventName' classVariableNames: '' poolDictionaries: '' category: 'ExtJsBuilder'! !EJClassDefinition methodsFor: 'accessing' stamp: 'lr 11/27/2007 15:42'! comment | input char result | input := comment contents readStream. result := String streamContents: [ :output | [ input atEnd ] whileFalse: [ char := input next. char caseOf: { [ $< ] -> [ input upTo: $> ]. [ $" ] -> [ output nextPut: $' ]. [ $@ ] -> [ char := input next. char = ${ ifTrue: [ output nextPutAll: (input upTo: $}) ] ifFalse: [ input upTo: $ ] ] } otherwise: [ output nextPut: char ] ] ]. ^ result withBlanksCondensed! ! !EJClassDefinition methodsFor: 'accessing' stamp: 'lr 11/27/2007 12:03'! configName ^ configName! ! !EJClassDefinition methodsFor: 'accessing' stamp: 'lr 11/27/2007 11:59'! configType ^ configType select: [ :each | each isAlphaNumeric ]! ! !EJClassDefinition methodsFor: 'accessing' stamp: 'lr 11/27/2007 08:49'! fileCategory | category | category := (filePath at: filePath size - 1) copy. category at: 1 put: category first asUppercase. ^ category! ! !EJClassDefinition methodsFor: 'accessing' stamp: 'lr 11/26/2007 22:16'! fileName ^ filePath last! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/27/2007 13:48'! initClass: aMatcher classSpace := aMatcher subexpression: 2. className := aMatcher subexpression: 4. (#( 'Array' 'Date' 'Function' 'Number' 'String' ) includes: className) ifTrue: [ ^ nil ]! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/27/2007 14:35'! initConfig: aMatcher configType := aMatcher subexpression: 2. configName := aMatcher subexpression: 3. comment nextPutAll: (aMatcher subexpression: 4); cr! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/26/2007 21:59'! initConstructor: aMatcher! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/27/2007 11:08'! initDeprecated: aMatcher ^ nil! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/27/2007 14:15'! initEvent: aMatcher eventName := aMatcher subexpression: 2! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/27/2007 13:48'! initExtends: aMatcher superSpace := aMatcher subexpression: 2. superName := aMatcher subexpression: 4! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/27/2007 11:13'! initFileName: aString filePath := aString findTokens: $/. (filePath includesAnyOf: #( 'adapter' 'legacy' 'locale' 'yui' )) ifTrue: [ ^ nil ]! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/27/2007 08:45'! initMember: aMatcher! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/26/2007 21:59'! initMethod: aMatcher! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/26/2007 21:59'! initParam: aMatcher! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/26/2007 21:59'! initPrivate: aMatcher! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/26/2007 21:59'! initProperty: aMatcher! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/26/2007 22:00'! initReturn: aMatcher! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/27/2007 13:38'! initSingleton: aMatcher singleton := true! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/26/2007 22:00'! initStatic: aMatcher! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/27/2007 14:34'! initUnknown: aString comment nextPutAll: aString; cr! ! !EJClassDefinition methodsFor: 'initialization' stamp: 'lr 11/26/2007 22:04'! initialize comment := WriteStream on: String new! ! !EJClassDefinition methodsFor: 'testing' stamp: 'lr 11/26/2007 22:09'! isClass ^ className notNil! ! !EJClassDefinition methodsFor: 'testing' stamp: 'lr 11/27/2007 11:53'! isConfig ^ configType notNil and: [ configName notNil ]! ! !EJClassDefinition methodsFor: 'testing' stamp: 'lr 11/27/2007 14:15'! isEvent ^ eventName notNil! ! !EJClassDefinition methodsFor: 'testing' stamp: 'lr 11/27/2007 13:38'! isSingleton ^ singleton ifNil: [ singleton := false ]! ! !EJClassDefinition methodsFor: 'accessing-javascript' stamp: 'lr 11/27/2007 13:48'! javascriptClassName ^ classSpace , className! ! !EJClassDefinition methodsFor: 'accessing-javascript' stamp: 'lr 11/27/2007 16:01'! javascriptEventName ^ eventName! ! !EJClassDefinition methodsFor: 'accessing-javascript' stamp: 'lr 11/27/2007 09:43'! javascriptSuperClassName ^ superSpace , superName! ! !EJClassDefinition methodsFor: 'printing' stamp: 'lr 11/26/2007 22:15'! printOn: aStream super printOn: aStream. aStream nextPutAll: ' fileName: '; print: filePath last! ! !EJClassDefinition methodsFor: 'accessing-smalltalk' stamp: 'lr 11/27/2007 14:09'! smalltalkClassName ^ self smalltalkName: className space: classSpace! ! !EJClassDefinition methodsFor: 'accessing-smalltalk' stamp: 'lr 11/27/2007 16:51'! smalltalkEventName "Get decent event names." | name | name := eventName copy. #('action' 'after' 'arrow' 'before' 'beforecell' 'beforecheck' 'beforechildren' 'beforecollapse' 'beforeexpand' 'beforenode' 'beforestate' 'beforetab' 'body' 'call' 'cell' 'cellcontext' 'celldbl' 'cellmouse' 'check' 'client' 'collapse' 'column' 'config' 'container' 'context' 'data' 'dbl' 'disabled' 'drag' 'editmode' 'end' 'expand' 'header' 'headercontext' 'headerdbl' 'headermouse' 'hidden' 'item' 'key' 'load' 'menu' 'menutrigger' 'meta' 'mouse' 'node' 'nodedrag' 'property' 'request' 'row' 'rowcontext' 'rowdbl' 'selection' 'sort' 'special' 'start' 'state' 'tab' 'text' 'title' 'validate' 'width') do: [ :each | (each size < name size and: [ name asLowercase beginsWith: each ]) ifTrue: [ name at: each size + 1 put: (name at: each size + 1) asUppercase ] ]. ^ 'on' , name capitalized! ! !EJClassDefinition methodsFor: 'accessing-smalltalk' stamp: 'lr 11/27/2007 16:40'! smalltalkName: aString space: aSpaceString "Get a decent smalltalk class name." ^ aString isNil ifFalse: [ String streamContents: [ :stream | stream nextPutAll: 'EJ'. (aSpaceString findTokens: $.) do: [ :each | (each = 'Ext' or: [ aString capitalized beginsWith: each capitalized ]) ifFalse: [ stream nextPutAll: each capitalized ] ]. stream nextPutAll: aString capitalized ] ]! ! !EJClassDefinition methodsFor: 'accessing-smalltalk' stamp: 'lr 11/27/2007 14:09'! smalltalkSuperName ^ (self smalltalkName: superName space: superSpace) ifNil: [ 'EJPrototype' ]! ! EJClassBuilder initialize!