text: // Copyright (c) Jupyter Development Team.
  // Distributed under the terms of the Modified BSD License.
  import { DocumentModel } from '@jupyterlab/docregistry';
  import { CodeCellModel, RawCellModel, MarkdownCellModel } from '@jupyterlab/cells';
  import * as nbformat from '@jupyterlab/nbformat';
  import { UUID } from '@lumino/coreutils';
  import { CellList } from './celllist';
  import { showDialog, Dialog } from '@jupyterlab/apputils';
  /**
   * An implementation of a notebook Model.
   */
  export class NotebookModel extends DocumentModel {
      /**
       * Construct a new notebook model.
       */
      constructor(options = {}) {
          super(options.languagePreference, options.modelDB);
          this._nbformat = nbformat.MAJOR_VERSION;
          this._nbformatMinor = nbformat.MINOR_VERSION;
          const factory = options.contentFactory || NotebookModel.defaultContentFactory;
          this.contentFactory = factory.clone(this.modelDB.view('cells'));
          this._cells = new CellList(this.modelDB, this.contentFactory);
          this._cells.changed.connect(this._onCellsChanged, this);
          // Handle initial metadata.
          const metadata = this.modelDB.createMap('metadata');
          if (!metadata.has('language_info')) {
              const name = options.languagePreference || '';
              metadata.set('language_info', { name });
          }
          this._ensureMetadata();
          metadata.changed.connect(this.triggerContentChange, this);
          this._deletedCells = [];
      }
      /**
       * The metadata associated with the notebook.
       */
      get metadata() {
          return this.modelDB.get('metadata');
      }
      /**
       * Get the observable list of notebook cells.
       */
      get cells() {
          return this._cells;
      }
      /**
       * The major version number of the nbformat.
       */
      get nbformat() {
          return this._nbformat;
      }
      /**
       * The minor version number of the nbformat.
       */
      get nbformatMinor() {
          return this._nbformatMinor;
      }
      /**
       * The default kernel name of the document.
       */
      get defaultKernelName() {
          const spec = this.metadata.get('kernelspec');
          return spec ? spec.name : '';
      }
      /**
       * A list of deleted cells for the notebook..
       */
      get deletedCells() {
          return this._deletedCells;
      }
      /**
       * The default kernel language of the document.
       */
      get defaultKernelLanguage() {
          const info = this.metadata.get('language_info');
          return info ? info.name : '';
      }
      /**
       * Dispose of the resources held by the model.
       */
      dispose() {
          // Do nothing if already disposed.
          if (this.isDisposed) {
              return;
          }
          const cells = this.cells;
          this._cells = null;
          cells.dispose();
          super.dispose();
      }
      /**
       * Serialize the model to a string.
       */
      toString() {
          return JSON.stringify(this.toJSON());
      }
      /**
       * Deserialize the model from a string.
       *
       * #### Notes
       * Should emit a [contentChanged] signal.
       */
      fromString(value) {
          this.fromJSON(JSON.parse(value));
      }
      /**
       * Serialize the model to JSON.
       */
      toJSON() {
          var _a;
          const cells = [];
          for (let i = 0; i < (((_a = this.cells) === null || _a === void 0 ? void 0 : _a.length) || 0); i++) {
              const cell = this.cells.get(i);
              cells.push(cell.toJSON());
          }
          this._ensureMetadata();
          const metadata = Object.create(null);
          for (const key of this.metadata.keys()) {
              metadata[key] = JSON.parse(JSON.stringify(this.metadata.get(key)));
          }
          return {
              metadata,
              nbformat_minor: this._nbformatMinor,
              nbformat: this._nbformat,
              cells
          };
      }
      /**
       * Deserialize the model from JSON.
       *
       * #### Notes
       * Should emit a [contentChanged] signal.
       */
      fromJSON(value) {
          const cells = [];
          const factory = this.contentFactory;
          for (const cell of value.cells) {
              switch (cell.cell_type) {
                  case 'code':
                      cells.push(factory.createCodeCell({ cell }));
                      break;
                  case 'markdown':
                      cells.push(factory.createMarkdownCell({ cell }));
                      break;
                  case 'raw':
                      cells.push(factory.createRawCell({ cell }));
                      break;
                  default:
                      continue;
              }
          }
          this.cells.beginCompoundOperation();
          this.cells.clear();
          this.cells.pushAll(cells);
          this.cells.endCompoundOperation();
          let oldValue = 0;
          let newValue = 0;
          this._nbformatMinor = nbformat.MINOR_VERSION;
          this._nbformat = nbformat.MAJOR_VERSION;
          const origNbformat = value.metadata.orig_nbformat;
          if (value.nbformat !== this._nbformat) {
              oldValue = this._nbformat;
              this._nbformat = newValue = value.nbformat;
              this.triggerStateChange({ name: 'nbformat', oldValue, newValue });
          }
          if (value.nbformat_minor > this._nbformatMinor) {
              oldValue = this._nbformatMinor;
              this._nbformatMinor = newValue = value.nbformat_minor;
              this.triggerStateChange({ name: 'nbformatMinor', oldValue, newValue });
          }
          // Alert the user if the format changes.
          if (origNbformat !== undefined && this._nbformat !== origNbformat) {
              const newer = this._nbformat > origNbformat;
              const msg = `This notebook has been converted from ${newer ? 'an older' : 'a newer'} notebook format (v${origNbformat}) to the current notebook format (v${this._nbformat}). The next time you save this notebook, the current notebook format (v${this._nbformat}) will be used. ${newer
                  ? 'Older versions of Jupyter may not be able to read the new format.'
                  : 'Some features of the original notebook may not be available.'}  To preserve the original format version, close the notebook without saving it.`;
              void showDialog({
                  title: 'Notebook converted',
                  body: msg,
                  buttons: [Dialog.okButton()]
              });
          }
          // Update the metadata.
          this.metadata.clear();
          const metadata = value.metadata;
          for (const key in metadata) {
              // orig_nbformat is not intended to be stored per spec.
              if (key === 'orig_nbformat') {
                  continue;
              }
              this.metadata.set(key, metadata[key]);
          }
          this._ensureMetadata();
          this.dirty = true;
      }
      /**
       * Initialize the model with its current state.
       *
       * # Notes
       * Adds an empty code cell if the model is empty
       * and clears undo state.
       */
      initialize() {
          super.initialize();
          if (!this.cells.length) {
              const factory = this.contentFactory;
              this.cells.push(factory.createCodeCell({}));
          }
          this.cells.clearUndo();
      }
      /**
       * Handle a change in the cells list.
       */
      _onCellsChanged(list, change) {
          switch (change.type) {
              case 'add':
                  change.newValues.forEach(cell => {
                      cell.contentChanged.connect(this.triggerContentChange, this);
                  });
                  break;
              case 'remove':
                  break;
              case 'set':
                  change.newValues.forEach(cell => {
                      cell.contentChanged.connect(this.triggerContentChange, this);
                  });
                  break;
              default:
                  break;
          }
          this.triggerContentChange();
      }
      /**
       * Make sure we have the required metadata fields.
       */
      _ensureMetadata() {
          const metadata = this.metadata;
          if (!metadata.has('language_info')) {
              metadata.set('language_info', { name: '' });
          }
          if (!metadata.has('kernelspec')) {
              metadata.set('kernelspec', { name: '', display_name: '' });
          }
      }
  }
  /**
   * The namespace for the `NotebookModel` class statics.
   */
  (function (NotebookModel) {
      /**
       * The default implementation of an `IContentFactory`.
       */
      class ContentFactory {
          /**
           * Create a new cell model factory.
           */
          constructor(options) {
              this.codeCellContentFactory =
                  options.codeCellContentFactory || CodeCellModel.defaultContentFactory;
              this.modelDB = options.modelDB;
          }
          /**
           * Create a new cell by cell type.
           *
           * @param type:  the type of the cell to create.
           *
           * @param options: the cell creation options.
           *
           * #### Notes
           * This method is intended to be a convenience method to programmaticaly
           * call the other cell creation methods in the factory.
           */
          createCell(type, opts) {
              switch (type) {
                  case 'code':
                      return this.createCodeCell(opts);
                  case 'markdown':
                      return this.createMarkdownCell(opts);
                  case 'raw':
                  default:
                      return this.createRawCell(opts);
              }
          }
          /**
           * Create a new code cell.
           *
           * @param source - The data to use for the original source data.
           *
           * @returns A new code cell. If a source cell is provided, the
           *   new cell will be initialized with the data from the source.
           *   If the contentFactory is not provided, the instance
           *   `codeCellContentFactory` will be used.
           */
          createCodeCell(options) {
              if (options.contentFactory) {
                  options.contentFactory = this.codeCellContentFactory;
              }
              if (this.modelDB) {
                  if (!options.id) {
                      options.id = UUID.uuid4();
                  }
                  options.modelDB = this.modelDB.view(options.id);
              }
              return new CodeCellModel(options);
          }
          /**
           * Create a new markdown cell.
           *
           * @param source - The data to use for the original source data.
           *
           * @returns A new markdown cell. If a source cell is provided, the
           *   new cell will be initialized with the data from the source.
           */
          createMarkdownCell(options) {
              if (this.modelDB) {
                  if (!options.id) {
                      options.id = UUID.uuid4();
                  }
                  options.modelDB = this.modelDB.view(options.id);
              }
              return new MarkdownCellModel(options);
          }
          /**
           * Create a new raw cell.
           *
           * @param source - The data to use for the original source data.
           *
           * @returns A new raw cell. If a source cell is provided, the
           *   new cell will be initialized with the data from the source.
           */
          createRawCell(options) {
              if (this.modelDB) {
                  if (!options.id) {
                      options.id = UUID.uuid4();
                  }
                  options.modelDB = this.modelDB.view(options.id);
              }
              return new RawCellModel(options);
          }
          /**
           * Clone the content factory with a new IModelDB.
           */
          clone(modelDB) {
              return new ContentFactory({
                  modelDB: modelDB,
                  codeCellContentFactory: this.codeCellContentFactory
              });
          }
      }
      NotebookModel.ContentFactory = ContentFactory;
      /**
       * The default `ContentFactory` instance.
       */
      NotebookModel.defaultContentFactory = new ContentFactory({});
  })(NotebookModel || (NotebookModel = {}));
  //# sourceMappingURL=model.js.map