Kernel-Infrastructure.st 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518
  1. Smalltalk createPackage: 'Kernel-Infrastructure'!
  2. Object subclass: #ConsoleErrorHandler
  3. instanceVariableNames: ''
  4. package: 'Kernel-Infrastructure'!
  5. !ConsoleErrorHandler commentStamp!
  6. I am manage Smalltalk errors, displaying the stack in the console.!
  7. !ConsoleErrorHandler methodsFor: 'error handling'!
  8. handleError: anError
  9. anError context ifNotNil: [ self logErrorContext: anError context ].
  10. self logError: anError
  11. ! !
  12. !ConsoleErrorHandler methodsFor: 'private'!
  13. log: aString
  14. console log: aString
  15. !
  16. logContext: aContext
  17. aContext home ifNotNil: [
  18. self logContext: aContext home ].
  19. self log: aContext asString
  20. !
  21. logError: anError
  22. self log: anError messageText
  23. !
  24. logErrorContext: aContext
  25. aContext ifNotNil: [
  26. aContext home ifNotNil: [
  27. self logContext: aContext home ]]
  28. ! !
  29. ConsoleErrorHandler class instanceVariableNames: 'current'!
  30. !ConsoleErrorHandler class methodsFor: 'initialization'!
  31. initialize
  32. ErrorHandler registerIfNone: self new
  33. ! !
  34. Object subclass: #InterfacingObject
  35. instanceVariableNames: ''
  36. package: 'Kernel-Infrastructure'!
  37. !InterfacingObject commentStamp!
  38. I am superclass of all object that interface with user or environment. `Widget` and a few other classes are subclasses of me. I delegate all of the above APIs to `PlatformInterface`.
  39. ## API
  40. self alert: 'Hey, there is a problem'.
  41. self confirm: 'Affirmative?'.
  42. self prompt: 'Your name:'.
  43. self ajax: #{
  44. 'url' -> '/patch.js'. 'type' -> 'GET'. dataType->'script'
  45. }.!
  46. !InterfacingObject methodsFor: 'actions'!
  47. ajax: anObject
  48. ^ PlatformInterface ajax: anObject
  49. !
  50. alert: aString
  51. ^ PlatformInterface alert: aString
  52. !
  53. confirm: aString
  54. ^ PlatformInterface confirm: aString
  55. !
  56. prompt: aString
  57. ^ PlatformInterface prompt: aString
  58. !
  59. prompt: aString default: defaultString
  60. ^ PlatformInterface prompt: aString default: defaultString
  61. ! !
  62. InterfacingObject subclass: #Environment
  63. instanceVariableNames: ''
  64. package: 'Kernel-Infrastructure'!
  65. !Environment commentStamp!
  66. I provide an unified entry point to manipulate Amber packages, classes and methods.
  67. Typical use cases include IDEs, remote access and restricting browsing.!
  68. !Environment methodsFor: 'accessing'!
  69. allSelectors
  70. ^ Smalltalk core allSelectors
  71. !
  72. availableClassNames
  73. ^ Smalltalk classes
  74. collect: [ :each | each name ]
  75. !
  76. availablePackageNames
  77. ^ Smalltalk packages
  78. collect: [ :each | each name ]
  79. !
  80. availableProtocolsFor: aClass
  81. | protocols |
  82. protocols := aClass protocols.
  83. aClass superclass ifNotNil: [ protocols addAll: (self availableProtocolsFor: aClass superclass) ].
  84. ^ protocols asSet asArray sort
  85. !
  86. classBuilder
  87. ^ ClassBuilder new
  88. !
  89. classNamed: aString
  90. ^ (Smalltalk globals at: aString asSymbol)
  91. ifNil: [ self error: 'Invalid class name' ]
  92. !
  93. classes
  94. ^ Smalltalk classes
  95. !
  96. doItReceiver
  97. ^ DoIt new
  98. !
  99. packages
  100. ^ Smalltalk packages
  101. !
  102. systemAnnouncer
  103. ^ (Smalltalk globals at: #SystemAnnouncer) current
  104. ! !
  105. !Environment methodsFor: 'actions'!
  106. commitPackage: aPackage onSuccess: aBlock onError: anotherBlock
  107. aPackage transport
  108. commitOnSuccess: aBlock
  109. onError: anotherBlock
  110. !
  111. copyClass: aClass to: aClassName
  112. (Smalltalk globals at: aClassName)
  113. ifNotNil: [ self error: 'A class named ', aClassName, ' already exists' ].
  114. ClassBuilder new copyClass: aClass named: aClassName
  115. !
  116. inspect: anObject
  117. Inspector inspect: anObject
  118. !
  119. moveClass: aClass toPackage: aPackageName
  120. | package |
  121. package := Package named: aPackageName.
  122. package ifNil: [ self error: 'Invalid package name' ].
  123. package == aClass package ifTrue: [ ^ self ].
  124. aClass package: package
  125. !
  126. moveMethod: aMethod toClass: aClassName
  127. | destinationClass |
  128. destinationClass := self classNamed: aClassName.
  129. destinationClass == aMethod methodClass ifTrue: [ ^ self ].
  130. aMethod methodClass isMetaclass ifTrue: [
  131. destinationClass := destinationClass class ].
  132. destinationClass
  133. compile: aMethod source
  134. protocol: aMethod protocol.
  135. aMethod methodClass
  136. removeCompiledMethod: aMethod
  137. !
  138. moveMethod: aMethod toProtocol: aProtocol
  139. aMethod protocol: aProtocol
  140. !
  141. removeClass: aClass
  142. Smalltalk removeClass: aClass
  143. !
  144. removeMethod: aMethod
  145. aMethod methodClass removeCompiledMethod: aMethod
  146. !
  147. removeProtocol: aString from: aClass
  148. (aClass methodsInProtocol: aString)
  149. do: [ :each | aClass removeCompiledMethod: each ]
  150. !
  151. renameClass: aClass to: aClassName
  152. (Smalltalk globals at: aClassName)
  153. ifNotNil: [ self error: 'A class named ', aClassName, ' already exists' ].
  154. ClassBuilder new renameClass: aClass to: aClassName
  155. !
  156. renameProtocol: aString to: anotherString in: aClass
  157. (aClass methodsInProtocol: aString)
  158. do: [ :each | each protocol: anotherString ]
  159. !
  160. setClassCommentOf: aClass to: aString
  161. aClass comment: aString
  162. ! !
  163. !Environment methodsFor: 'compiling'!
  164. addInstVarNamed: aString to: aClass
  165. self classBuilder
  166. addSubclassOf: aClass superclass
  167. named: aClass name
  168. instanceVariableNames: (aClass instanceVariableNames copy add: aString; yourself)
  169. package: aClass package name
  170. !
  171. compileClassComment: aString for: aClass
  172. aClass comment: aString
  173. !
  174. compileClassDefinition: aString
  175. [ self evaluate: aString for: DoIt new ]
  176. on: Error
  177. do: [ :error | self alert: error messageText ]
  178. !
  179. compileMethod: sourceCode for: class protocol: protocol
  180. ^ class
  181. compile: sourceCode
  182. protocol: protocol
  183. ! !
  184. !Environment methodsFor: 'error handling'!
  185. evaluate: aBlock on: anErrorClass do: exceptionBlock
  186. "Evaluate a block and catch exceptions happening on the environment stack"
  187. aBlock tryCatch: [ :exception |
  188. (exception isKindOf: (self classNamed: anErrorClass name))
  189. ifTrue: [ exceptionBlock value: exception ]
  190. ifFalse: [ exception resignal ] ]
  191. ! !
  192. !Environment methodsFor: 'evaluating'!
  193. evaluate: aString for: anObject
  194. ^ Evaluator evaluate: aString for: anObject
  195. ! !
  196. !Environment methodsFor: 'services'!
  197. registerErrorHandler: anErrorHandler
  198. ErrorHandler register: anErrorHandler
  199. !
  200. registerFinder: aFinder
  201. Finder register: aFinder
  202. !
  203. registerInspector: anInspector
  204. Inspector register: anInspector
  205. !
  206. registerProgressHandler: aProgressHandler
  207. ProgressHandler register: aProgressHandler
  208. !
  209. registerTranscript: aTranscript
  210. Transcript register: aTranscript
  211. ! !
  212. ProtoObject subclass: #JSObjectProxy
  213. instanceVariableNames: 'jsObject'
  214. package: 'Kernel-Infrastructure'!
  215. !JSObjectProxy commentStamp!
  216. I handle sending messages to JavaScript objects, making JavaScript object accessing from Amber fully transparent.
  217. My instances make intensive use of `#doesNotUnderstand:`.
  218. My instances are automatically created by Amber whenever a message is sent to a JavaScript object.
  219. ## Usage examples
  220. JSObjectProxy objects are instanciated by Amber when a Smalltalk message is sent to a JavaScript object.
  221. window alert: 'hello world'.
  222. window inspect.
  223. (window jQuery: 'body') append: 'hello world'
  224. Amber messages sends are converted to JavaScript function calls or object property access _(in this order)_. If n one of them match, a `MessageNotUnderstood` error will be thrown.
  225. ## Message conversion rules
  226. - `someUser name` becomes `someUser.name`
  227. - `someUser name: 'John'` becomes `someUser name = "John"`
  228. - `console log: 'hello world'` becomes `console.log('hello world')`
  229. - `(window jQuery: 'foo') css: 'background' color: 'red'` becomes `window.jQuery('foo').css('background', 'red')`
  230. __Note:__ For keyword-based messages, only the first keyword is kept: `window foo: 1 bar: 2` is equivalent to `window foo: 1 baz: 2`.!
  231. !JSObjectProxy methodsFor: 'accessing'!
  232. at: aString
  233. <return self['@jsObject'][aString]>
  234. !
  235. at: aString ifAbsent: aBlock
  236. "return the aString property or evaluate aBlock if the property is not defined on the object"
  237. <
  238. var obj = self['@jsObject'];
  239. return aString in obj ? obj[aString] : aBlock._value();
  240. >
  241. !
  242. at: aString ifPresent: aBlock
  243. "return the evaluation of aBlock with the value if the property is defined or return nil"
  244. <
  245. var obj = self['@jsObject'];
  246. return aString in obj ? aBlock._value_(obj[aString]) : nil;
  247. >
  248. !
  249. at: aString ifPresent: aBlock ifAbsent: anotherBlock
  250. "return the evaluation of aBlock with the value if the property is defined
  251. or return value of anotherBlock"
  252. <
  253. var obj = self['@jsObject'];
  254. return aString in obj ? aBlock._value_(obj[aString]) : anotherBlock._value();
  255. >
  256. !
  257. at: aString put: anObject
  258. <return self['@jsObject'][aString] = anObject>
  259. !
  260. jsObject
  261. ^ jsObject
  262. ! !
  263. !JSObjectProxy methodsFor: 'comparing'!
  264. = anObject
  265. anObject class == self class ifFalse: [ ^ false ].
  266. ^ JSObjectProxy compareJSObjectOfProxy: self withProxy: anObject
  267. ! !
  268. !JSObjectProxy methodsFor: 'enumerating'!
  269. asJSON
  270. "Answers the receiver in a stringyfy-friendly fashion"
  271. ^ jsObject
  272. !
  273. keysAndValuesDo: aBlock
  274. <
  275. var o = self['@jsObject'];
  276. for(var i in o) {
  277. aBlock._value_value_(i, o[i]);
  278. }
  279. >
  280. ! !
  281. !JSObjectProxy methodsFor: 'printing'!
  282. printOn: aStream
  283. aStream nextPutAll: self printString
  284. !
  285. printString
  286. <
  287. var js = self['@jsObject'];
  288. return js.toString
  289. ? js.toString()
  290. : Object.prototype.toString.call(js)
  291. >
  292. ! !
  293. !JSObjectProxy methodsFor: 'proxy'!
  294. doesNotUnderstand: aMessage
  295. ^ (JSObjectProxy lookupProperty: aMessage selector asJavaScriptPropertyName ofProxy: self)
  296. ifNil: [ super doesNotUnderstand: aMessage ]
  297. ifNotNil: [ :jsSelector |
  298. JSObjectProxy
  299. forwardMessage: jsSelector
  300. withArguments: aMessage arguments
  301. ofProxy: self ]
  302. !
  303. inspectOn: anInspector
  304. | variables |
  305. variables := Dictionary new.
  306. variables at: '#self' put: self jsObject.
  307. anInspector setLabel: self printString.
  308. JSObjectProxy addObjectVariablesTo: variables ofProxy: self.
  309. anInspector setVariables: variables
  310. ! !
  311. !JSObjectProxy class methodsFor: 'instance creation'!
  312. on: aJSObject
  313. | instance |
  314. instance := self new.
  315. self jsObject: aJSObject ofProxy: instance.
  316. ^ instance
  317. ! !
  318. !JSObjectProxy class methodsFor: 'proxy'!
  319. addObjectVariablesTo: aDictionary ofProxy: aProxy
  320. <
  321. var jsObject = aProxy['@jsObject'];
  322. for(var i in jsObject) {
  323. aDictionary._at_put_(i, jsObject[i]);
  324. }
  325. >
  326. !
  327. compareJSObjectOfProxy: aProxy withProxy: anotherProxy
  328. <
  329. var anotherJSObject = anotherProxy.klass ? anotherProxy["@jsObject"] : anotherProxy;
  330. return aProxy["@jsObject"] === anotherJSObject
  331. >
  332. !
  333. forwardMessage: aString withArguments: anArray ofProxy: aProxy
  334. <
  335. return $core.accessJavaScript(aProxy._jsObject(), aString, anArray);
  336. >
  337. !
  338. jsObject: aJSObject ofProxy: aProxy
  339. <aProxy['@jsObject'] = aJSObject>
  340. !
  341. lookupProperty: aString ofProxy: aProxy
  342. "Looks up a property in JS object.
  343. Answer the property if it is present, or nil if it is not present."
  344. <return aString in aProxy._jsObject() ? aString : nil>
  345. ! !
  346. Object subclass: #NullProgressHandler
  347. instanceVariableNames: ''
  348. package: 'Kernel-Infrastructure'!
  349. !NullProgressHandler commentStamp!
  350. I am the default progress handler. I do not display any progress, and simply iterate over the collection.!
  351. !NullProgressHandler methodsFor: 'progress handling'!
  352. do: aBlock on: aCollection displaying: aString
  353. aCollection do: aBlock
  354. ! !
  355. NullProgressHandler class instanceVariableNames: 'current'!
  356. !NullProgressHandler class methodsFor: 'initialization'!
  357. initialize
  358. ProgressHandler registerIfNone: self new
  359. ! !
  360. Object subclass: #Organizer
  361. instanceVariableNames: ''
  362. package: 'Kernel-Infrastructure'!
  363. !Organizer commentStamp!
  364. I represent categorization information.
  365. ## API
  366. Use `#addElement:` and `#removeElement:` to manipulate instances.!
  367. !Organizer methodsFor: 'accessing'!
  368. addElement: anObject
  369. <self.elements.addElement(anObject)>
  370. !
  371. elements
  372. ^ (self basicAt: 'elements') copy
  373. !
  374. removeElement: anObject
  375. <self.elements.removeElement(anObject)>
  376. ! !
  377. Organizer subclass: #ClassOrganizer
  378. instanceVariableNames: ''
  379. package: 'Kernel-Infrastructure'!
  380. !ClassOrganizer commentStamp!
  381. I am an organizer specific to classes. I hold method categorization information for classes.!
  382. !ClassOrganizer methodsFor: 'accessing'!
  383. addElement: aString
  384. super addElement: aString.
  385. SystemAnnouncer current announce: (ProtocolAdded new
  386. protocol: aString;
  387. theClass: self theClass;
  388. yourself)
  389. !
  390. removeElement: aString
  391. super removeElement: aString.
  392. SystemAnnouncer current announce: (ProtocolRemoved new
  393. protocol: aString;
  394. theClass: self theClass;
  395. yourself)
  396. !
  397. theClass
  398. < return self.theClass >
  399. ! !
  400. Organizer subclass: #PackageOrganizer
  401. instanceVariableNames: ''
  402. package: 'Kernel-Infrastructure'!
  403. !PackageOrganizer commentStamp!
  404. I am an organizer specific to packages. I hold classes categorization information.!
  405. Object subclass: #Package
  406. instanceVariableNames: 'transport imports dirty'
  407. package: 'Kernel-Infrastructure'!
  408. !Package commentStamp!
  409. I am similar to a "class category" typically found in other Smalltalks like Pharo or Squeak. Amber does not have class categories anymore, it had in the beginning but now each class in the system knows which package it belongs to.
  410. Each package has a name and can be queried for its classes, but it will then resort to a reverse scan of all classes to find them.
  411. ## API
  412. Packages are manipulated through "Smalltalk current", like for example finding one based on a name or with `Package class >> #name` directly:
  413. Smalltalk current packageAt: 'Kernel'
  414. Package named: 'Kernel'
  415. A package differs slightly from a Monticello package which can span multiple class categories using a naming convention based on hyphenation. But just as in Monticello a package supports "class extensions" so a package can define behaviors in foreign classes using a naming convention for method categories where the category starts with an asterisk and then the name of the owning package follows.
  416. You can fetch a package from the server:
  417. Package load: 'Additional-Examples'!
  418. !Package methodsFor: 'accessing'!
  419. beClean
  420. dirty := false.
  421. SystemAnnouncer current announce: (PackageClean new
  422. package: self;
  423. yourself)
  424. !
  425. beDirty
  426. dirty := true.
  427. SystemAnnouncer current announce: (PackageDirty new
  428. package: self;
  429. yourself)
  430. !
  431. classTemplate
  432. ^ String streamContents: [ :stream |
  433. stream
  434. nextPutAll: 'Object';
  435. nextPutAll: ' subclass: #NameOfSubclass';
  436. nextPutAll: String lf, String tab;
  437. nextPutAll: 'instanceVariableNames: '''''.
  438. stream
  439. nextPutAll: '''', String lf, String tab;
  440. nextPutAll: 'package: ''';
  441. nextPutAll: self name;
  442. nextPutAll: '''' ]
  443. !
  444. definition
  445. ^ String streamContents: [ :stream |
  446. stream
  447. nextPutAll: self class name;
  448. nextPutAll: String lf, String tab;
  449. nextPutAll: 'named: ';
  450. nextPutAll: '''', self name, '''';
  451. nextPutAll: String lf, String tab;
  452. nextPutAll: 'imports: ';
  453. nextPutAll: self importsDefinition;
  454. nextPutAll: String lf, String tab;
  455. nextPutAll: 'transport: (';
  456. nextPutAll: self transport definition, ')' ]
  457. !
  458. imports
  459. ^ imports ifNil: [
  460. | parsed |
  461. parsed := self importsFromJson: self basicImports.
  462. self imports: parsed.
  463. imports ]
  464. !
  465. imports: anArray
  466. self validateImports: anArray.
  467. imports := anArray asSet
  468. !
  469. importsDefinition
  470. ^ String streamContents: [ :stream |
  471. stream nextPutAll: '{'.
  472. self sortedImportsAsArray
  473. do: [ :each | stream nextPutAll: each importsString ]
  474. separatedBy: [ stream nextPutAll: '. ' ].
  475. stream nextPutAll: '}' ]
  476. !
  477. name
  478. <return self.pkgName>
  479. !
  480. name: aString
  481. self basicName: aString.
  482. self beDirty
  483. !
  484. organization
  485. ^ self basicAt: 'organization'
  486. !
  487. transport
  488. ^ transport ifNil: [
  489. transport := (PackageTransport fromJson: self basicTransport)
  490. package: self;
  491. yourself ]
  492. !
  493. transport: aPackageTransport
  494. transport := aPackageTransport.
  495. aPackageTransport package: self
  496. ! !
  497. !Package methodsFor: 'classes'!
  498. classes
  499. ^ self organization elements
  500. !
  501. setupClasses
  502. self classes
  503. do: [ :each | ClassBuilder new setupClass: each ];
  504. do: [ :each | each initialize ]
  505. !
  506. sortedClasses
  507. "Answer all classes in the receiver, sorted by superclass/subclasses and by class name for common subclasses (Issue #143)."
  508. ^ self class sortedClasses: self classes
  509. ! !
  510. !Package methodsFor: 'converting'!
  511. importsAsJson
  512. ^ self sortedImportsAsArray collect: [ :each |
  513. each isString
  514. ifTrue: [ each ]
  515. ifFalse: [ each key, '=', each value ]]
  516. !
  517. importsFromJson: anArray
  518. "Parses array of string, eg. #('asdf' 'qwer=tyuo')
  519. into array of Strings and Associations,
  520. eg. {'asdf'. 'qwer'->'tyuo'}"
  521. ^ anArray collect: [ :each |
  522. | split |
  523. split := each tokenize: '='.
  524. split size = 1
  525. ifTrue: [ split first ]
  526. ifFalse: [ split first -> split second ]]
  527. ! !
  528. !Package methodsFor: 'dependencies'!
  529. loadDependencies
  530. "Returns list of packages that need to be loaded
  531. before loading this package."
  532. | classes packages |
  533. classes := self loadDependencyClasses.
  534. ^ (classes collect: [ :each | each package ]) asSet
  535. remove: self ifAbsent: [];
  536. yourself
  537. !
  538. loadDependencyClasses
  539. "Returns classes needed at the time of loading a package.
  540. These are all that are used to subclass
  541. and to define an extension method"
  542. | starCategoryName |
  543. starCategoryName := '*', self name.
  544. ^ (self classes collect: [ :each | each superclass ]) asSet
  545. remove: nil ifAbsent: [];
  546. addAll: (Smalltalk classes select: [ :each | each protocols, each class protocols includes: starCategoryName ]);
  547. yourself
  548. ! !
  549. !Package methodsFor: 'printing'!
  550. printOn: aStream
  551. super printOn: aStream.
  552. aStream
  553. nextPutAll: ' (';
  554. nextPutAll: self name;
  555. nextPutAll: ')'
  556. ! !
  557. !Package methodsFor: 'private'!
  558. basicImports
  559. "Answer the imports literal JavaScript object as setup in the JavaScript file, if any"
  560. <return self.imports || []>
  561. !
  562. basicName: aString
  563. <self.pkgName = aString>
  564. !
  565. basicTransport
  566. "Answer the transport literal JavaScript object as setup in the JavaScript file, if any"
  567. <return self.transport>
  568. !
  569. sortedImportsAsArray
  570. "Answer imports sorted first by type (associations first),
  571. then by value"
  572. ^ self imports asArray
  573. sorted: [ :a :b |
  574. a isString not & b isString or: [
  575. a isString = b isString and: [
  576. a value <= b value ]]]
  577. ! !
  578. !Package methodsFor: 'testing'!
  579. isDirty
  580. ^ dirty ifNil: [ false ]
  581. !
  582. isPackage
  583. ^ true
  584. ! !
  585. !Package methodsFor: 'validation'!
  586. validateImports: aCollection
  587. aCollection do: [ :import |
  588. import isString ifFalse: [
  589. (import respondsTo: #key) ifFalse: [
  590. self error: 'Imports must be Strings or Associations' ].
  591. import key isString & import value isString ifFalse: [
  592. self error: 'Key and value must be Strings' ].
  593. (import key match: '^[a-zA-Z][a-zA-Z0-9]*$') ifFalse: [
  594. self error: 'Keys must be identifiers' ]]]
  595. ! !
  596. Package class instanceVariableNames: 'defaultCommitPathJs defaultCommitPathSt'!
  597. !Package class methodsFor: 'accessing'!
  598. named: aPackageName
  599. ^ Smalltalk
  600. packageAt: aPackageName
  601. ifAbsent: [
  602. Smalltalk createPackage: aPackageName ]
  603. !
  604. named: aPackageName ifAbsent: aBlock
  605. ^ Smalltalk packageAt: aPackageName ifAbsent: aBlock
  606. !
  607. named: aPackageName imports: anArray transport: aTransport
  608. | package |
  609. package := self named: aPackageName.
  610. package imports: anArray.
  611. package transport: aTransport.
  612. ^ package
  613. !
  614. named: aPackageName transport: aTransport
  615. | package |
  616. package := self named: aPackageName.
  617. package transport: aTransport.
  618. ^ package
  619. ! !
  620. !Package class methodsFor: 'sorting'!
  621. sortedClasses: classes
  622. "Answer classes, sorted by superclass/subclasses and by class name for common subclasses (Issue #143)"
  623. | children others nodes expandedClasses |
  624. children := #().
  625. others := #().
  626. classes do: [ :each |
  627. (classes includes: each superclass)
  628. ifFalse: [ children add: each ]
  629. ifTrue: [ others add: each ]].
  630. nodes := children collect: [ :each |
  631. ClassSorterNode on: each classes: others level: 0 ].
  632. nodes := nodes sorted: [ :a :b | a theClass name <= b theClass name ].
  633. expandedClasses := Array new.
  634. nodes do: [ :aNode |
  635. aNode traverseClassesWith: expandedClasses ].
  636. ^ expandedClasses
  637. ! !
  638. Object subclass: #PackageStateObserver
  639. instanceVariableNames: ''
  640. package: 'Kernel-Infrastructure'!
  641. !PackageStateObserver commentStamp!
  642. My current instance listens for any changes in the system that might affect the state of a package (being dirty).!
  643. !PackageStateObserver methodsFor: 'accessing'!
  644. announcer
  645. ^ SystemAnnouncer current
  646. ! !
  647. !PackageStateObserver methodsFor: 'actions'!
  648. observeSystem
  649. self announcer
  650. on: PackageAdded
  651. send: #onPackageAdded:
  652. to: self;
  653. on: ClassAnnouncement
  654. send: #onClassModification:
  655. to: self;
  656. on: MethodAnnouncement
  657. send: #onMethodModification:
  658. to: self;
  659. on: ProtocolAnnouncement
  660. send: #onProtocolModification:
  661. to: self
  662. ! !
  663. !PackageStateObserver methodsFor: 'reactions'!
  664. onClassModification: anAnnouncement
  665. anAnnouncement theClass ifNotNil: [ :theClass | theClass package beDirty ]
  666. !
  667. onMethodModification: anAnnouncement
  668. anAnnouncement method package ifNotNil: [ :package | package beDirty ]
  669. !
  670. onPackageAdded: anAnnouncement
  671. anAnnouncement package beDirty
  672. !
  673. onProtocolModification: anAnnouncement
  674. anAnnouncement package ifNotNil: [ :package | package beDirty ]
  675. ! !
  676. PackageStateObserver class instanceVariableNames: 'current'!
  677. !PackageStateObserver class methodsFor: 'accessing'!
  678. current
  679. ^ current ifNil: [ current := self new ]
  680. ! !
  681. !PackageStateObserver class methodsFor: 'initialization'!
  682. initialize
  683. self current observeSystem
  684. ! !
  685. Object subclass: #PlatformInterface
  686. instanceVariableNames: ''
  687. package: 'Kernel-Infrastructure'!
  688. !PlatformInterface commentStamp!
  689. I am single entry point to UI and environment interface.
  690. My `initialize` tries several options (for now, browser environment only) to set myself up.
  691. ## API
  692. PlatformInterface alert: 'Hey, there is a problem'.
  693. PlatformInterface confirm: 'Affirmative?'.
  694. PlatformInterface prompt: 'Your name:'.
  695. PlatformInterface ajax: #{
  696. 'url' -> '/patch.js'. 'type' -> 'GET'. dataType->'script'
  697. }.!
  698. PlatformInterface class instanceVariableNames: 'worker'!
  699. !PlatformInterface class methodsFor: 'accessing'!
  700. globals
  701. <return (new Function('return this'))();>
  702. !
  703. setWorker: anObject
  704. worker := anObject
  705. ! !
  706. !PlatformInterface class methodsFor: 'actions'!
  707. ajax: anObject
  708. ^ worker
  709. ifNotNil: [ worker ajax: anObject ]
  710. ifNil: [ self error: 'ajax: not available' ]
  711. !
  712. alert: aString
  713. ^ worker
  714. ifNotNil: [ worker alert: aString ]
  715. ifNil: [ self error: 'alert: not available' ]
  716. !
  717. confirm: aString
  718. ^ worker
  719. ifNotNil: [ worker confirm: aString ]
  720. ifNil: [ self error: 'confirm: not available' ]
  721. !
  722. existsGlobal: aString
  723. ^ PlatformInterface globals
  724. at: aString
  725. ifPresent: [ true ]
  726. ifAbsent: [ false ]
  727. !
  728. prompt: aString
  729. ^ worker
  730. ifNotNil: [ worker prompt: aString ]
  731. ifNil: [ self error: 'prompt: not available' ]
  732. !
  733. prompt: aString default: defaultString
  734. ^ worker
  735. ifNotNil: [ worker prompt: aString default: defaultString ]
  736. ifNil: [ self error: 'prompt: not available' ]
  737. ! !
  738. !PlatformInterface class methodsFor: 'initialization'!
  739. initialize
  740. | candidate |
  741. super initialize.
  742. BrowserInterface ifNotNil: [
  743. candidate := BrowserInterface new.
  744. candidate isAvailable ifTrue: [ self setWorker: candidate. ^ self ]
  745. ]
  746. ! !
  747. Object subclass: #Service
  748. instanceVariableNames: ''
  749. package: 'Kernel-Infrastructure'!
  750. !Service commentStamp!
  751. I implement the basic behavior for class registration to a service.
  752. See the `Transcript` class for a concrete service.
  753. ## API
  754. Use class-side methods `#register:` and `#registerIfNone:` to register classes to a specific service.!
  755. Service class instanceVariableNames: 'current'!
  756. !Service class methodsFor: 'accessing'!
  757. current
  758. ^ current
  759. ! !
  760. !Service class methodsFor: 'instance creation'!
  761. new
  762. self shouldNotImplement
  763. ! !
  764. !Service class methodsFor: 'registration'!
  765. register: anObject
  766. current := anObject
  767. !
  768. registerIfNone: anObject
  769. self current ifNil: [ self register: anObject ]
  770. ! !
  771. Service subclass: #ErrorHandler
  772. instanceVariableNames: ''
  773. package: 'Kernel-Infrastructure'!
  774. !ErrorHandler commentStamp!
  775. I am the service used to handle Smalltalk errors.
  776. See `boot.js` `handleError()` function.
  777. Registered service instances must implement `#handleError:` to perform an action on the thrown exception.!
  778. !ErrorHandler class methodsFor: 'error handling'!
  779. handleError: anError
  780. self handleUnhandledError: anError
  781. !
  782. handleUnhandledError: anError
  783. anError wasHandled ifTrue: [ ^ self ].
  784. ^ self current handleError: anError
  785. ! !
  786. Service subclass: #Finder
  787. instanceVariableNames: ''
  788. package: 'Kernel-Infrastructure'!
  789. !Finder commentStamp!
  790. I am the service responsible for finding classes/methods.
  791. __There is no default finder.__
  792. ## API
  793. Use `#browse` on an object to find it.!
  794. !Finder class methodsFor: 'finding'!
  795. findClass: aClass
  796. ^ self current findClass: aClass
  797. !
  798. findMethod: aCompiledMethod
  799. ^ self current findMethod: aCompiledMethod
  800. !
  801. findString: aString
  802. ^ self current findString: aString
  803. ! !
  804. Service subclass: #Inspector
  805. instanceVariableNames: ''
  806. package: 'Kernel-Infrastructure'!
  807. !Inspector commentStamp!
  808. I am the service responsible for inspecting objects.
  809. The default inspector object is the transcript.!
  810. !Inspector class methodsFor: 'inspecting'!
  811. inspect: anObject
  812. ^ self current inspect: anObject
  813. ! !
  814. Service subclass: #ProgressHandler
  815. instanceVariableNames: ''
  816. package: 'Kernel-Infrastructure'!
  817. !ProgressHandler commentStamp!
  818. I am used to manage progress in collection iterations, see `SequenceableCollection >> #do:displayingProgress:`.
  819. Registered instances must implement `#do:on:displaying:`.
  820. The default behavior is to simply iterate over the collection, using `NullProgressHandler`.!
  821. !ProgressHandler class methodsFor: 'progress handling'!
  822. do: aBlock on: aCollection displaying: aString
  823. self current do: aBlock on: aCollection displaying: aString
  824. ! !
  825. Service subclass: #Transcript
  826. instanceVariableNames: ''
  827. package: 'Kernel-Infrastructure'!
  828. !Transcript commentStamp!
  829. I am a facade for Transcript actions.
  830. I delegate actions to the currently registered transcript.
  831. ## API
  832. Transcript
  833. show: 'hello world';
  834. cr;
  835. show: anObject.!
  836. !Transcript class methodsFor: 'instance creation'!
  837. open
  838. self current open
  839. ! !
  840. !Transcript class methodsFor: 'printing'!
  841. clear
  842. self current clear
  843. !
  844. cr
  845. self current show: String cr
  846. !
  847. inspect: anObject
  848. self show: anObject
  849. !
  850. show: anObject
  851. self current show: anObject
  852. ! !
  853. Object subclass: #Setting
  854. instanceVariableNames: 'key value defaultValue'
  855. package: 'Kernel-Infrastructure'!
  856. !Setting commentStamp!
  857. I represent a setting **stored** at `Smalltalk settings`.
  858. In the current implementation, `Smalltalk settings` is an object persisted in the localStorage.
  859. ## API
  860. A `Setting` value can be read using `value` and set using `value:`.
  861. Settings are accessed with `'key' asSetting` or `'key' asSettingIfAbsent: aDefaultValue`.
  862. To read the value of a setting you can also use the convenience:
  863. `theValueSet := 'any.characteristic' settingValue`
  864. or with a default using:
  865. `theEnsuredValueSet := 'any.characteristic' settingValueIfAbsent: true`!
  866. !Setting methodsFor: 'accessing'!
  867. defaultValue
  868. ^ defaultValue
  869. !
  870. defaultValue: aStringifiableObject
  871. defaultValue := aStringifiableObject
  872. !
  873. key
  874. ^ key
  875. !
  876. key: aString
  877. key := aString
  878. !
  879. value
  880. ^ Smalltalk settings at: self key ifAbsent: [ self defaultValue ]
  881. !
  882. value: aStringifiableObject
  883. ^ Smalltalk settings at: self key put: aStringifiableObject
  884. ! !
  885. !Setting class methodsFor: 'instance creation'!
  886. at: aString ifAbsent: aDefaultValue
  887. ^ super new
  888. key: aString;
  889. defaultValue: aDefaultValue;
  890. yourself
  891. !
  892. new
  893. self shouldNotImplement
  894. ! !
  895. Object subclass: #SmalltalkImage
  896. instanceVariableNames: ''
  897. package: 'Kernel-Infrastructure'!
  898. !SmalltalkImage commentStamp!
  899. I represent the Smalltalk system, wrapping
  900. operations of variable `$core` declared in `support/boot.js`.
  901. ## API
  902. I have only one instance, accessed with global variable `Smalltalk`.
  903. ## Classes
  904. Classes can be accessed using the following methods:
  905. - `#classes` answers the full list of Smalltalk classes in the system
  906. - `#globals #at:` answers a specific global (usually, a class) or `nil`
  907. ## Packages
  908. Packages can be accessed using the following methods:
  909. - `#packages` answers the full list of packages
  910. - `#packageAt:` answers a specific package or `nil`
  911. ## Parsing
  912. The `#parse:` method is used to parse Amber source code.
  913. It requires the `Compiler` package and the `support/parser.js` parser file in order to work.!
  914. !SmalltalkImage methodsFor: 'accessing'!
  915. cancelOptOut: anObject
  916. "A Smalltalk object has a 'klass' property.
  917. If this property is shadowed for anObject by optOut:,
  918. the object is treated as plain JS object.
  919. This removes the shadow and anObject is Smalltalk object
  920. again if it was before."
  921. <delete anObject.klass>
  922. !
  923. core
  924. <return $core>
  925. !
  926. globals
  927. <return $globals>
  928. !
  929. includesKey: aKey
  930. <return $core.hasOwnProperty(aKey)>
  931. !
  932. optOut: anObject
  933. "A Smalltalk object has a 'klass' property.
  934. This shadows the property for anObject.
  935. The object is treated as plain JS object following this."
  936. <anObject.klass = null>
  937. !
  938. parse: aString
  939. | result |
  940. [ result := self basicParse: aString ]
  941. tryCatch: [ :ex | (self parseError: ex parsing: aString) signal ].
  942. ^ result
  943. source: aString;
  944. yourself
  945. !
  946. pseudoVariableNames
  947. ^ #('self' 'super' 'nil' 'true' 'false' 'thisContext')
  948. !
  949. readJSObject: anObject
  950. <return $core.readJSObject(anObject)>
  951. !
  952. reservedWords
  953. "JavaScript reserved words"
  954. <return $core.reservedWords>
  955. !
  956. settings
  957. ^ SmalltalkSettings
  958. !
  959. version
  960. "Answer the version string of Amber"
  961. ^ '0.15.0-pre'
  962. ! !
  963. !SmalltalkImage methodsFor: 'accessing amd'!
  964. amdRequire
  965. ^ self core at: 'amdRequire'
  966. !
  967. defaultAmdNamespace
  968. ^ 'transport.defaultAmdNamespace' settingValue
  969. !
  970. defaultAmdNamespace: aString
  971. 'transport.defaultAmdNamespace' settingValue: aString
  972. ! !
  973. !SmalltalkImage methodsFor: 'classes'!
  974. classes
  975. <return $core.classes()>
  976. !
  977. removeClass: aClass
  978. aClass isMetaclass ifTrue: [ self error: aClass asString, ' is a Metaclass and cannot be removed!!' ].
  979. self deleteClass: aClass.
  980. SystemAnnouncer current
  981. announce: (ClassRemoved new
  982. theClass: aClass;
  983. yourself)
  984. ! !
  985. !SmalltalkImage methodsFor: 'error handling'!
  986. asSmalltalkException: anObject
  987. "A JavaScript exception may be thrown.
  988. We then need to convert it back to a Smalltalk object"
  989. ^ ((self isSmalltalkObject: anObject) and: [ anObject isKindOf: Error ])
  990. ifTrue: [ anObject ]
  991. ifFalse: [ JavaScriptException on: anObject ]
  992. !
  993. parseError: anException parsing: aString
  994. ^ ParseError new messageText: 'Parse error on line ', (anException basicAt: 'line') ,' column ' , (anException basicAt: 'column') ,' : Unexpected character ', (anException basicAt: 'found')
  995. ! !
  996. !SmalltalkImage methodsFor: 'globals'!
  997. addGlobalJsVariable: aString
  998. self globalJsVariables add: aString
  999. !
  1000. deleteGlobalJsVariable: aString
  1001. self globalJsVariables remove: aString ifAbsent:[]
  1002. !
  1003. globalJsVariables
  1004. "Array of global JavaScript variables"
  1005. <return $core.globalJsVariables>
  1006. ! !
  1007. !SmalltalkImage methodsFor: 'packages'!
  1008. createPackage: packageName
  1009. | package announcement |
  1010. package := self basicCreatePackage: packageName.
  1011. announcement := PackageAdded new
  1012. package: package;
  1013. yourself.
  1014. SystemAnnouncer current announce: announcement.
  1015. ^ package
  1016. !
  1017. packageAt: packageName
  1018. <return $core.packages[packageName]>
  1019. !
  1020. packageAt: packageName ifAbsent: aBlock
  1021. ^ (self packageAt: packageName) ifNil: aBlock
  1022. !
  1023. packages
  1024. "Return all Package instances in the system."
  1025. <
  1026. return Object.keys($core.packages).map(function(k) {
  1027. return $core.packages[k];
  1028. })
  1029. >
  1030. !
  1031. removePackage: packageName
  1032. "Removes a package and all its classes."
  1033. | pkg |
  1034. pkg := self packageAt: packageName ifAbsent: [ self error: 'Missing package: ', packageName ].
  1035. pkg classes do: [ :each |
  1036. self removeClass: each ].
  1037. self deletePackage: packageName
  1038. !
  1039. renamePackage: packageName to: newName
  1040. "Rename a package."
  1041. | pkg |
  1042. pkg := self packageAt: packageName ifAbsent: [ self error: 'Missing package: ', packageName ].
  1043. (self packageAt: newName) ifNotNil: [ self error: 'Already exists a package called: ', newName ].
  1044. pkg name: newName.
  1045. self basicRegisterPackage: pkg.
  1046. self deletePackage: packageName.
  1047. ! !
  1048. !SmalltalkImage methodsFor: 'private'!
  1049. basicCreatePackage: packageName
  1050. "Create and bind a new bare package with given name and return it."
  1051. <return $core.addPackage(packageName)>
  1052. !
  1053. basicParse: aString
  1054. ^ SmalltalkParser parse: aString
  1055. !
  1056. basicRegisterPackage: aPackage
  1057. "Put aPackage in $core.packages object."
  1058. <$core.packages[aPackage.pkgName]=aPackage>
  1059. !
  1060. deleteClass: aClass
  1061. "Deletes a class by deleting its binding only. Use #removeClass instead"
  1062. <$core.removeClass(aClass)>
  1063. !
  1064. deletePackage: packageName
  1065. "Deletes a package by deleting its binding, but does not check if it contains classes etc.
  1066. To remove a package, use #removePackage instead."
  1067. <delete $core.packages[packageName]>
  1068. ! !
  1069. !SmalltalkImage methodsFor: 'testing'!
  1070. isSmalltalkObject: anObject
  1071. "Consider anObject a Smalltalk object if it has a 'klass' property.
  1072. Note that this may be unaccurate"
  1073. <return typeof anObject.klass !!== 'undefined'>
  1074. ! !
  1075. SmalltalkImage class instanceVariableNames: 'current'!
  1076. !SmalltalkImage class methodsFor: 'initialization'!
  1077. initialize
  1078. | st |
  1079. st := self current.
  1080. st globals at: 'Smalltalk' put: st
  1081. ! !
  1082. !SmalltalkImage class methodsFor: 'instance creation'!
  1083. current
  1084. ^ current ifNil: [ current := super new ] ifNotNil: [ self deprecatedAPI. current ]
  1085. !
  1086. new
  1087. self shouldNotImplement
  1088. ! !
  1089. !Association methodsFor: '*Kernel-Infrastructure'!
  1090. importsString
  1091. "This is for use by package exporter.
  1092. It can fail for non-string keys and values."
  1093. ^ self key importsString, ' -> ', self value importsString
  1094. ! !
  1095. !SequenceableCollection methodsFor: '*Kernel-Infrastructure'!
  1096. do: aBlock displayingProgress: aString
  1097. ProgressHandler
  1098. do: aBlock
  1099. on: self
  1100. displaying: aString
  1101. ! !
  1102. !String methodsFor: '*Kernel-Infrastructure'!
  1103. asJavaScriptPropertyName
  1104. <return $core.st2prop(self)>
  1105. !
  1106. asSetting
  1107. "Answer aSetting dedicated to locally store a value using this string as key.
  1108. Nil will be the default value."
  1109. ^ Setting at: self ifAbsent: nil
  1110. !
  1111. asSettingIfAbsent: aDefaultValue
  1112. "Answer aSetting dedicated to locally store a value using this string as key.
  1113. Make this setting to have aDefaultValue."
  1114. ^ Setting at: self ifAbsent: aDefaultValue
  1115. !
  1116. importsString
  1117. "Answer receiver as Smalltalk expression"
  1118. ^ '''', (self replace: '''' with: ''''''), ''''
  1119. !
  1120. settingValue
  1121. ^ self asSetting value
  1122. !
  1123. settingValue: aValue
  1124. "Sets the value of the setting that will be locally stored using this string as key.
  1125. Note that aValue can be any object that can be stringifyed"
  1126. ^ self asSetting value: aValue
  1127. !
  1128. settingValueIfAbsent: aDefaultValue
  1129. "Answer the value of the locally stored setting using this string as key.
  1130. Use aDefaultValue in case no setting is found"
  1131. ^ (self asSettingIfAbsent: aDefaultValue) value
  1132. ! !