28 | {% endset %}
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Pennebaker
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/library/_partials/README.md:
--------------------------------------------------------------------------------
1 | # Partials & Modular Content Management
2 |
3 | The partials section has to do primarily with blocks within Matrix fields. The models contained within are made to be copied and pasted into a Matrix field as block-level objects. See below for an example:
4 |
5 | ```
6 | {
7 | "group": "Default",
8 | "name": "Matrix",
9 | "handle": "matrix",
10 | "instructions": "Use this area to build out content for this page.",
11 | "type": "Matrix",
12 | "typesettings": {
13 | "blockTypes":{
14 | "new1": // Copy and paste the entire block-level model here, including the curly braces.
15 | }
16 | }
17 | }
18 | ```
19 |
20 | The `new1` object shown above doesn't have braces that defines it as an object, because each partial/block-level model includes the braces that define it. This ensures that each block-level model validates when run through a linter.
21 |
22 | Block-level models in the partials directory are not configured to drag and drop into the Generator as solo fields. They lack the proper structure for the plugin to read them properly. They are meant to be added as is to a Matrix field type.
23 |
24 | ## Examples
25 | Examples will be added to the [Plugin Wiki](https://github.com/Pennebaker/craftcms-generator/wiki/Block-Examples).
26 |
--------------------------------------------------------------------------------
/library/executive-bios.json:
--------------------------------------------------------------------------------
1 | {
2 | "groups":[
3 | "Executive Bios"
4 | ],
5 | "fields": [
6 | {
7 | "group": "Executive Bios",
8 | "name": "Display Name",
9 | "handle": "displayName",
10 | "type": "PlainText",
11 | "instructions": "Whose bio is this?"
12 | },
13 | {
14 | "group": "Executive Bios",
15 | "name": "Job Title",
16 | "handle": "jobTitle",
17 | "type": "PlainText",
18 | "instructions": "What's their job title?"
19 | },
20 | {
21 | "group": "Executive Bios",
22 | "name": "Bio Content",
23 | "handle": "bio",
24 | "type": "RichText",
25 | "instructions": "The content of the bio itself.",
26 | "typesettings": {
27 | "configFile": "Simple"
28 | }
29 | },
30 | {
31 | "group": "Executive Bios",
32 | "name": "Bio Photo",
33 | "handle": "bioPhoto",
34 | "instructions": "Usually a headshot.",
35 | "type": "Assets",
36 | "typesettings": {
37 | "restrictFiles": true,
38 | "allowedKinds": [
39 | "image"
40 | ],
41 | "selectionLabel": "Select an image"
42 | }
43 | }
44 | ],
45 | "entryTypes": [
46 | {
47 | "sectionName": "Executive Bios",
48 | "name":"Executive Bios",
49 | "handle":"bios",
50 | "titleLabel": "CMS Title",
51 | "fieldLayout": {
52 | "Bio": [
53 | "Display Name",
54 | "Job Title",
55 | "Bio Content",
56 | "Bio Photo"
57 | ]
58 | }
59 | }
60 | ]
61 | }
62 |
--------------------------------------------------------------------------------
/thearchitect/controllers/TheArchitect_ApiController.php:
--------------------------------------------------------------------------------
1 | theArchitect->getAPIKey();
15 | $key = craft()->request->getParam('key');
16 |
17 | if (!$apiKey OR $key != $apiKey) {
18 | die('{"type": "export","success": false}');
19 | }
20 |
21 | // Run Migration Export
22 | craft()->theArchitect->exportMigrationConstruct();
23 |
24 | // Set last import to match this export time.
25 | craft()->plugins->savePluginSettings(craft()->plugins->getPlugin('theArchitect'), array('lastImport' => (new DateTime())->getTimestamp()));
26 |
27 | die('{"type": "export","success": true}');
28 | }
29 |
30 | public function actionImport()
31 | {
32 | $apiKey = craft()->theArchitect->getAPIKey();
33 | $key = craft()->request->getParam('key');
34 | $force = craft()->request->getParam('force');
35 |
36 | if (!$apiKey OR $key != $apiKey) {
37 | die('{"type": "export","success": false}');
38 | }
39 |
40 | // Run Migration Import
41 | $result = craft()->theArchitect->importMigrationConstruct($force);
42 |
43 | if ($result) {
44 | die('{"type": "import","success": true}');
45 | } else {
46 | die('{"type": "import","success": false}');
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/library/meta-data.json:
--------------------------------------------------------------------------------
1 | {
2 | "groups":[
3 | "Meta Data"
4 | ],
5 | "fields": [
6 | {
7 | "group": "Meta Data",
8 | "name": "SEO Title",
9 | "instructions": "The page title that appears on SERPs and bookmarks.",
10 | "type": "PlainText"
11 | },
12 | {
13 | "group": "Meta Data",
14 | "name": "SEO Description",
15 | "instructions": "The page description that appears on SERPs.",
16 | "type": "PlainText"
17 | },
18 | {
19 | "group": "Meta Data",
20 | "name": "OpenGraph Title",
21 | "instructions": "The OpenGraph title that appears on Facebook, LinkedIn, and other social sites. Try to limit to 90 characters.",
22 | "type": "PlainText"
23 | },
24 | {
25 | "group": "Meta Data",
26 | "name": "OpenGraph Description",
27 | "instructions": "The OpenGraph description that appears on Facebook, LinkedIn, and other social sites. Try to limit to 300 characters.",
28 | "type": "PlainText"
29 | },
30 | {
31 | "group": "Meta Data",
32 | "name": "OpenGraph Image",
33 | "instructions": "The OpenGraph image that appears on Facebook, LinkedIn, and other social sites.",
34 | "type": "Assets",
35 | "typesettings": {
36 | "restrictFiles": true,
37 | "allowedKinds": [
38 | "image"
39 | ],
40 | "limit": 1,
41 | "selectionLabel": "Add an OpenGraph image."
42 | }
43 | },
44 | {
45 | "group": "Meta Data",
46 | "name": "OpenGraph URL",
47 | "instructions": "The canonical url for this entry.",
48 | "type": "PlainText"
49 | }
50 | ]
51 | }
52 |
--------------------------------------------------------------------------------
/library/_partials/block-call-to-action.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Call to Action Block",
3 | "handle": "ctaBlock",
4 | "instructions": "This block is used to incite action in your user.",
5 | "fields": {
6 | "new1": {
7 | "name": "headline",
8 | "handle": "headline",
9 | "instructions": "The headline for this block.",
10 | "type": "PlainText"
11 | },
12 | "new2": {
13 | "name": "CTA Copy",
14 | "handle": "blockCopy",
15 | "instructions": "The copy that precedes the button.",
16 | "type": "RichText",
17 | "typesettings": {
18 | "configFile": "Simple"
19 | }
20 | },
21 | "new3": {
22 | "name": "Background Image",
23 | "handle": "blockBgImg",
24 | "instructions": "The background image for this block.",
25 | "type": "Assets",
26 | "typesettings": {
27 | "restrictFiles": true,
28 | "allowedKinds": [
29 | "image"
30 | ],
31 | "limit": 1,
32 | "selectionLabel": "Select an Image"
33 | }
34 | },
35 | "new4": {
36 | "name": "Block Background Color",
37 | "handle": "blockBgColor",
38 | "instructions": "Is the background white or gray?",
39 | "type": "Dropdown",
40 | "typesettings": {
41 | "options": [
42 | {
43 | "label": "White",
44 | "value": "white",
45 | "default": true
46 | },
47 | {
48 | "label": "Gray",
49 | "value": "gray",
50 | "default": false
51 | }
52 | ]
53 | }
54 | },
55 | "new5": {
56 | "name": "Button Text",
57 | "handle": "buttonText",
58 | "instructions": "The text for the button.",
59 | "type": "PlainText"
60 | },
61 | "new6": {
62 | "name": "Destination",
63 | "handle": "buttonDestination",
64 | "instructions": "Where does the button go when you click it?",
65 | "type": "Entries",
66 | "typesettings": {
67 | "limit": 1,
68 | "selectionLabel": "Select a Destination"
69 | }
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/thearchitect/templates/output.twig:
--------------------------------------------------------------------------------
1 | {% extends "_layouts/cp" %}
2 | {% set title = "The Architect"|t %}
3 |
4 | {% import "_includes/forms" as forms %}
5 |
6 | {% set tabs = {
7 | tab1: { label: "Raw Input"|t, url: url('thearchitect') },
8 | tab2: { label: "Available Files"|t, url: url('thearchitect/files') },
9 | tab3: { label: "Export"|t, url: url('thearchitect/blueprint') },
10 | tab4: { label: "Migrations"|t, url: url('thearchitect/migrations') },
11 | tab5: { label: "Matrix to Neo Export"|t, url: url('thearchitect/convert') },
12 | } %}
13 |
14 | {% set selectedTab = tab %}
15 |
16 | {% set content %}
17 |
18 |
19 | {% if selectedTab == 'tab5' %}
20 |
21 | To import this json back into Craft you will need the Neo Plugin installed.
22 |
23 |
24 | If you plan on re-importing this json directly into this instance of Craft remember to rename the handle either in this json model or on the old matrix field.
25 |
26 |
27 | {{ oldFieldCount }} fields found in matrix field(s) reduced to {{ newFieldCount }} fields used by Neo
28 |
29 | {% endif %}
30 | {# Text Area for Output Data #}
31 | {{ forms.textarea({
32 | name: 'json',
33 | class: 'nicetext code',
34 | value: (json is defined ? json : null),
35 | first: true,
36 | autofocus: true,
37 | rows: 24
38 | }) }}
39 | {% if similarFields is defined and similarFields | length %}
40 |
Some similar fields you might want to review and combine manually.
41 |
42 |
43 |
44 |
45 | Field A
46 |
47 |
48 | Field B
49 |
50 |
51 |
52 |
53 | {% for fields in similarFields %}
54 |
55 |
56 |
{{ fields.A }}
57 |
58 |
59 |
{{ fields.B }}
60 |
61 |
62 | {% endfor %}
63 |
64 |
65 | {% endif %}
66 |
67 |
68 | {% endset %}
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Looking for? [Architect for Craft 3/4](https://github.com/Pennebaker/craft-architect)
2 |
3 | 
4 | # The Architect for [Craft CMS](http://buildwithcraft.com/)
5 |
6 | CraftCMS Plugin to Construct Groups, Fields, Sections, EntryTypes, Transforms, Globals, Assets, Categories, and Users & User Groups from JSON data.
7 |
8 | ## Installation
9 | 1. Move the `thearchitect` directory into your `craft/plugins` directory.
10 | 2. Go to Settings > Plugins from your Craft control panel and enable the `thearchitect` plugin
11 |
12 | Example files can be found in the `library` directory
13 |
14 | ## Exported Constructs
15 | If you want to provide json files to be loaded throught the CP. Put the files in `craft/config/thearchitect`. If using a version prior to v1.6.0 the folder for these files is `craft/plugins/thearchitect/content`. This path is also configurable by creating a config file at `craft/config/thearchitect.php`
16 | ```php
17 | 'modelsPath' => str_replace('plugins', 'config', __dir__.'/'),
18 | ```
19 |
20 | ## Migration File
21 | The migration file is named `_master_.json` and located inside the folder with the other json files listed above. Migration files are intended to be used within a single site. They are not intended to transfer content models between websites.
22 |
23 | ## Rollback
24 | As of version 1.6.0, if Craft crashes with an exception, the Architect will attempt to roll back any changes that were made to the database for the operation. This should help prevent any issues that might appear from a partial import. If an exception happens please report them to on the [repo's issues](https://github.com/Pennebaker/craftcms-thearchitect/issues). A backup that was created during a migration that was successfully imported will be delete. Otherwise you can find the db backup inside `craft/storage/backups`. This is in case the rollback feature doesn't restore properly. It is not recommended to rely on this auto backup/restore feature.
25 |
26 | ## JSON Schema
27 | The example / syntax schemas are located on the [Repo's Wiki](https://github.com/Pennebaker/craftcms-thearchitect/wiki)
28 |
29 | If you're using the [Atom text editor](https://atom.io/), you can download a [snippet library](https://github.com/Emkaytoo/craft-json-snippets) to help speed up your writing custom models for the plugin.
30 |
31 | ## Field Layouts using names instead of handles
32 | If you have some field layouts that use names this functionality was dropped in version 1.0.3. Alternatively you can update your old models to use handles to fix them for newer versions.
33 |
34 | *Special thanks to [Shannon Threadgill](https://dribbble.com/threadgillthunder) for his totally boss illustrations.*
35 |
--------------------------------------------------------------------------------
/thearchitect/variables/TheArchitectVariable.php:
--------------------------------------------------------------------------------
1 | neo->getBlockTypesByFieldId($layoutId);
16 | }
17 |
18 | /**
19 | * Returns an array of all the users.
20 | *
21 | * @return array[UserModel]
22 | */
23 | public function getAllUsers()
24 | {
25 | return craft()->theArchitect->getAllUsers();
26 | }
27 |
28 | /**
29 | * Returns an array of all the users.
30 | *
31 | * @return array[UserModel]
32 | */
33 | public function getAllTagGroups()
34 | {
35 | return craft()->tags->getAllTagGroups();
36 | }
37 |
38 | /**
39 | * Returns a entry type by its ID.
40 | *
41 | * @param int $entryTypeId
42 | *
43 | * @return EntryTypeModel|null
44 | */
45 | public function getEntryTypeById($entryTypeId)
46 | {
47 | return craft()->sections->getEntryTypeById($entryTypeId);
48 | }
49 |
50 | /**
51 | * Returns a asset source by its ID.
52 | *
53 | * @param int $sourceId
54 | *
55 | * @return AssetSourceModel|null
56 | */
57 | public function getSourceById($sourceId)
58 | {
59 | return craft()->assetSources->getSourceById($sourceId);
60 | }
61 |
62 | /**
63 | * Returns a asset transform by its ID.
64 | *
65 | * @param int $transformId
66 | *
67 | * @return AssetTransformModel|null
68 | */
69 | public function getTransformById($transformId)
70 | {
71 | foreach (craft()->assetTransforms->getAllTransforms() as $transform) {
72 | if ($transform->id == $transformId) {
73 | return $transform;
74 | }
75 | }
76 | }
77 |
78 | /**
79 | * Returns a category group by its ID.
80 | *
81 | * @param int $categoryId
82 | *
83 | * @return CategoryGroupModel|null
84 | */
85 | public function getCategoryGroupById($categoryId)
86 | {
87 | foreach (craft()->categories->getAllGroups() as $category) {
88 | if ($category->id == $categoryId) {
89 | return $category;
90 | }
91 | }
92 | }
93 |
94 | /**
95 | * Returns a user by its ID.
96 | *
97 | * @param int $userId
98 | *
99 | * @return UserModel|null
100 | */
101 | public function getUserById($userId)
102 | {
103 | return craft()->users->getUserById($userId);
104 | }
105 |
106 | /**
107 | * Returns a integer of the license edition
108 | *
109 | * @return Integer
110 | */
111 | public function getEdition()
112 | {
113 | return craft()->getEdition();
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/thearchitect/templates/convert.twig:
--------------------------------------------------------------------------------
1 | {% extends "_layouts/cp" %}
2 | {% set title = "The Architect"|t %}
3 |
4 | {% import "_includes/forms" as forms %}
5 |
6 | {% set tabs = {
7 | tab1: { label: "Raw Input"|t, url: url('thearchitect') },
8 | tab2: { label: "Available Files"|t, url: url('thearchitect/files') },
9 | tab3: { label: "Export"|t, url: url('thearchitect/blueprint') },
10 | tab4: { label: "Migrations"|t, url: url('thearchitect/migrations') },
11 | tab5: { label: "Matrix to Neo Export"|t, url: url('thearchitect/convert') },
12 | } %}
13 |
14 | {% set selectedTab = 'tab5' %}
15 |
16 | {% set content %}
17 |
18 |
19 |
20 | The converted model will need the Neo Plugin installed on that Craft instance.
21 |
22 |
23 | Fields pulled out of matrix entries will be put in the same group the matrix field was in. The conversion will combine fields if they are 100% identical and that field will be grouped into the first group it was added as.
24 |
Migrations have only been tested in a local dev environment. Backup your DB before and while using migrations. Please report any issues you run into.
55 |
It is recommended leaving Automatic Import disabled until you have imported many times successfully with no issues or until the plugin has had some more real world testing.
56 |
Migrations are designed to be used with a single site only. Exported files store ID numbers of all exported data. When imported it will overwrite those IDs which could be different across sites. Using migrations to replicate models across sites is not the intended use.
57 |
58 |
59 |
60 |
Status
61 |
Migration file for import / export is located at: {{ jsonPath }}_master_.json.
62 |
If automatic import is enabled this is the file that will be loaded into the DB whenever the files modified time is newer than the last import time.
63 |
64 |
65 |
66 |
Automatic Import
67 |
{% if automation %}Enabled{% else %}Disabled{% endif %}
{{ quickActionForm('generateKey', 'Generate New Key') }}
94 |
95 |
96 |
{{ apiExportUrl }}
97 |
{{ clipboardButton(apiExportUrl) }}
98 |
99 |
100 |
{{ apiImportUrl }}
101 |
{{ clipboardButton(apiImportUrl) }}
102 |
103 |
104 |
105 | {% else %}
106 | {{ quickActionForm('generateKey', 'Generate Key') }}
107 | {% endif %}
108 |
109 |
110 |
111 | {% if dbAdditions|length > 0 %}
112 | {% include 'thearchitect/_itemTable' with {itemList: dbAdditions, status: 'success', headline: 'DB Additions', text: 'List of items added since the previous export. Performing an import will not delete these added fields.'} %}
113 | {% endif %}
114 | {% if dbUpdates|length > 0 %}
115 | {% include 'thearchitect/_itemTable' with {itemList: dbUpdates, status: 'warning', headline: 'DB Updates', text: 'List of items updated since the previous export. Performing an import will overwrite these changes prefering the exported model.'} %}
116 | {% endif %}
117 | {% if dbDeletions|length > 0 %}
118 | {% include 'thearchitect/_itemTable' with {itemList: dbDeletions, status: 'error', headline: 'DB Deletions', text: 'List if items deleted since the previous export. Performing an import will add these items back to the database.'} %}
119 | {% endif %}
120 | {% if modelAdditions|length > 0 %}
121 | {% include 'thearchitect/_itemTable' with {itemList: modelAdditions, status: 'success', headline: 'Model Additions', text: 'List if items added to the model since the previous import. Performing an import will create these items in the database.'} %}
122 | {% endif %}
123 | {% if modelUpdates|length > 0 %}
124 | {% include 'thearchitect/_itemTable' with {itemList: modelUpdates, status: 'warning', headline: 'Model Updates', text: 'List if items updated in the model since the previous import. Performing an import will modify existing items in the database.'} %}
125 | {% endif %}
126 | {% if modelDeletions|length > 0 %}
127 | {% include 'thearchitect/_itemTable' with {itemList: modelDeletions, status: 'error', headline: 'Model Deletions', text: 'List if items deleted from the model since the previous import. Performing an import will delete these items from the database.', subText: {Users: 'User deletions are not handled by The Architect please manually delete the users below to remove them.'}} %}
128 | {% endif %}
129 | {% if mismatch|length > 0 %}
130 |
Field Migration Problems
131 |
Problems listed below are preventing standard and automation imports from running. Please review changes before forcing an import.
132 |
133 |
134 |
135 |
Group
136 |
Name
137 |
Handle
138 |
Type
139 |
140 |
141 |
142 | {% for fields in mismatch %}
143 |
414 | {% endset %}
415 |
--------------------------------------------------------------------------------
/thearchitect/resources/js/diff.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 |
3 | diff v2.2.3
4 |
5 | Software License Agreement (BSD License)
6 |
7 | Copyright (c) 2009-2015, Kevin Decker
8 |
9 | All rights reserved.
10 |
11 | Redistribution and use of this software in source and binary forms, with or without modification,
12 | are permitted provided that the following conditions are met:
13 |
14 | * Redistributions of source code must retain the above
15 | copyright notice, this list of conditions and the
16 | following disclaimer.
17 |
18 | * Redistributions in binary form must reproduce the above
19 | copyright notice, this list of conditions and the
20 | following disclaimer in the documentation and/or other
21 | materials provided with the distribution.
22 |
23 | * Neither the name of Kevin Decker nor the names of its
24 | contributors may be used to endorse or promote products
25 | derived from this software without specific prior
26 | written permission.
27 |
28 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
29 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
30 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
31 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
34 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
35 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 | @license
37 | */
38 | !function(a,b){"object"==typeof exports&&"object"==typeof module?module.exports=b():"function"==typeof define&&define.amd?define([],b):"object"==typeof exports?exports.JsDiff=b():a.JsDiff=b()}(this,function(){/******/
39 | return function(a){/******/
40 | // The require function
41 | /******/
42 | function b(d){/******/
43 | // Check if module is in cache
44 | /******/
45 | if(c[d])/******/
46 | return c[d].exports;/******/
47 | // Create a new module (and put it into the cache)
48 | /******/
49 | var e=c[d]={/******/
50 | exports:{},/******/
51 | id:d,/******/
52 | loaded:!1};/******/
53 | // Return the exports of the module
54 | /******/
55 | /******/
56 | // Execute the module function
57 | /******/
58 | /******/
59 | // Flag the module as loaded
60 | /******/
61 | return a[d].call(e.exports,e,e.exports,b),e.loaded=!0,e.exports}// webpackBootstrap
62 | /******/
63 | // The module cache
64 | /******/
65 | var c={};/******/
66 | // Load entry module and return exports
67 | /******/
68 | /******/
69 | // expose the modules object (__webpack_modules__)
70 | /******/
71 | /******/
72 | // expose the module cache
73 | /******/
74 | /******/
75 | // __webpack_public_path__
76 | /******/
77 | return b.m=a,b.c=c,b.p="",b(0)}([/* 0 */
78 | /***/
79 | function(a,b,c){/*istanbul ignore start*/
80 | "use strict";/*istanbul ignore start*/
81 | function d(a){return a&&a.__esModule?a:{"default":a}}b.__esModule=!0,b.canonicalize=b.convertChangesToXML=b.convertChangesToDMP=b.parsePatch=b.applyPatches=b.applyPatch=b.createPatch=b.createTwoFilesPatch=b.structuredPatch=b.diffJson=b.diffCss=b.diffSentences=b.diffTrimmedLines=b.diffLines=b.diffWordsWithSpace=b.diffWords=b.diffChars=b.Diff=void 0;/*istanbul ignore end*/
82 | var/*istanbul ignore start*/e=c(1),f=d(e),/*istanbul ignore start*/g=c(2),/*istanbul ignore start*/h=c(3),/*istanbul ignore start*/i=c(5),/*istanbul ignore start*/j=c(6),/*istanbul ignore start*/k=c(7),/*istanbul ignore start*/l=c(8),/*istanbul ignore start*/m=c(9),/*istanbul ignore start*/n=c(10),/*istanbul ignore start*/o=c(12),/*istanbul ignore start*/p=c(13),/*istanbul ignore start*/q=c(14);/* See LICENSE file for terms of use */
83 | /*
84 | * Text diff implementation.
85 | *
86 | * This library supports the following APIS:
87 | * JsDiff.diffChars: Character by character diff
88 | * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace
89 | * JsDiff.diffLines: Line based diff
90 | *
91 | * JsDiff.diffCss: Diff targeted at CSS content
92 | *
93 | * These methods are based on the implementation proposed in
94 | * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986).
95 | * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927
96 | */
97 | b.Diff=f["default"],/*istanbul ignore start*/
98 | b.diffChars=g.diffChars,/*istanbul ignore start*/
99 | b.diffWords=h.diffWords,/*istanbul ignore start*/
100 | b.diffWordsWithSpace=h.diffWordsWithSpace,/*istanbul ignore start*/
101 | b.diffLines=i.diffLines,/*istanbul ignore start*/
102 | b.diffTrimmedLines=i.diffTrimmedLines,/*istanbul ignore start*/
103 | b.diffSentences=j.diffSentences,/*istanbul ignore start*/
104 | b.diffCss=k.diffCss,/*istanbul ignore start*/
105 | b.diffJson=l.diffJson,/*istanbul ignore start*/
106 | b.structuredPatch=o.structuredPatch,/*istanbul ignore start*/
107 | b.createTwoFilesPatch=o.createTwoFilesPatch,/*istanbul ignore start*/
108 | b.createPatch=o.createPatch,/*istanbul ignore start*/
109 | b.applyPatch=m.applyPatch,/*istanbul ignore start*/
110 | b.applyPatches=m.applyPatches,/*istanbul ignore start*/
111 | b.parsePatch=n.parsePatch,/*istanbul ignore start*/
112 | b.convertChangesToDMP=p.convertChangesToDMP,/*istanbul ignore start*/
113 | b.convertChangesToXML=q.convertChangesToXML,/*istanbul ignore start*/
114 | b.canonicalize=l.canonicalize},/* 1 */
115 | /***/
116 | function(a,b){/*istanbul ignore start*/
117 | "use strict";function c(){}function d(a,b,c,d,e){for(var f=0,g=b.length,h=0,i=0;g>f;f++){var j=b[f];if(j.removed){
118 | // Reverse add and remove so removes are output first to match common convention
119 | // The diffing algorithm is tied to add then remove output and this is the simplest
120 | // route to get the desired output with minimal overhead.
121 | if(j.value=d.slice(i,i+j.count).join(""),i+=j.count,f&&b[f-1].added){var k=b[f-1];b[f-1]=b[f],b[f]=k}}else{if(!j.added&&e){var l=c.slice(h,h+j.count);l=l.map(function(a,b){var c=d[i+b];return c.length>a.length?c:a}),j.value=l.join("")}else j.value=c.slice(h,h+j.count).join("");h+=j.count,
122 | // Common case
123 | j.added||(i+=j.count)}}
124 | // Special case handle for when one terminal is ignored. For this case we merge the
125 | // terminal into the prior string and drop the change.
126 | var m=b[g-1];return g>1&&(m.added||m.removed)&&a.equals("",m.value)&&(b[g-2].value+=m.value,b.pop()),b}function e(a){return{newPos:a.newPos,components:a.components.slice(0)}}b.__esModule=!0,b["default"]=/*istanbul ignore end*/c,c.prototype={/*istanbul ignore start*/
127 | /*istanbul ignore end*/
128 | diff:function(a,b){function c(a){return h?(setTimeout(function(){h(void 0,a)},0),!0):a}
129 | // Main worker method. checks all permutations of a given edit length for acceptance.
130 | function f(){for(var f=-1*l;l>=f;f+=2){var g=void 0,h=n[f-1],m=n[f+1],o=(m?m.newPos:0)-f;h&&(
131 | // No one else is going to attempt to use this value, clear it
132 | n[f-1]=void 0);var p=h&&h.newPos+1=0&&k>o;if(p||q){
133 | // If we have hit the end of both strings, then we are done
134 | if(
135 | // Select the diagonal that we want to branch from. We select the prior
136 | // path whose position in the new string is the farthest from the origin
137 | // and does not pass the bounds of the diff graph
138 | !p||q&&h.newPos=j&&o+1>=k)return c(d(i,g.components,b,a,i.useLongestToken));
139 | // Otherwise track this path as a potential candidate and continue.
140 | n[f]=g}else
141 | // If this path is a terminal then prune
142 | n[f]=void 0}l++}/*istanbul ignore start*/
143 | var/*istanbul ignore end*/g=arguments.length<=2||void 0===arguments[2]?{}:arguments[2],h=g.callback;"function"==typeof g&&(h=g,g={}),this.options=g;var i=this;a=this.castInput(a),b=this.castInput(b),a=this.removeEmpty(this.tokenize(a)),b=this.removeEmpty(this.tokenize(b));var j=b.length,k=a.length,l=1,m=j+k,n=[{newPos:-1,components:[]}],o=this.extractCommon(n[0],b,a,0);if(n[0].newPos+1>=j&&o+1>=k)
144 | // Identity per the equality and tokenizer
145 | return c([{value:b.join(""),count:b.length}]);
146 | // Performs the length of edit iteration. Is a bit fugly as this has to support the
147 | // sync and async mode which is never fun. Loops over execEditLength until a value
148 | // is produced.
149 | if(h)!function q(){setTimeout(function(){
150 | // This should not happen, but we want to be safe.
151 | /* istanbul ignore next */
152 | // This should not happen, but we want to be safe.
153 | /* istanbul ignore next */
154 | return l>m?h():void(f()||q())},0)}();else for(;m>=l;){var p=f();if(p)return p}},/*istanbul ignore start*/
155 | /*istanbul ignore end*/
156 | pushComponent:function(a,b,c){var d=a[a.length-1];d&&d.added===b&&d.removed===c?
157 | // We need to clone here as the component clone operation is just
158 | // as shallow array clone
159 | a[a.length-1]={count:d.count+1,added:b,removed:c}:a.push({count:1,added:b,removed:c})},/*istanbul ignore start*/
160 | /*istanbul ignore end*/
161 | extractCommon:function(a,b,c,d){for(var e=b.length,f=c.length,g=a.newPos,h=g-d,i=0;e>g+1&&f>h+1&&this.equals(b[g+1],c[h+1]);)g++,h++,i++;return i&&a.components.push({count:i}),a.newPos=g,h},/*istanbul ignore start*/
162 | /*istanbul ignore end*/
163 | equals:function(a,b){return a===b},/*istanbul ignore start*/
164 | /*istanbul ignore end*/
165 | removeEmpty:function(a){for(var b=[],c=0;ck))return!1;b++}}return!0}/*istanbul ignore start*/
223 | var/*istanbul ignore end*/d=arguments.length<=2||void 0===arguments[2]?{}:arguments[2];if("string"==typeof b&&(b=/*istanbul ignore start*/(0,g.parsePatch)(b)),Array.isArray(b)){if(b.length>1)throw new Error("applyPatch only works with a single input.");b=b[0]}
224 | // Search best fit offsets for each hunk based on the previous ones
225 | for(var e=a.split("\n"),f=b.hunks,h=d.compareLine||function(a,b,c,d){/*istanbul ignore end*/
226 | return b===d},j=0,k=d.fuzzFactor||0,l=0,m=0,n=void 0,o=void 0,p=0;p=a+g)return g;f=!0}
270 | // Check if trying to fit before text beginning, and if not, check it fits
271 | // before offset location
272 | return e?void 0:(f||(d=!0),a-g>=b?-g++:(e=!0,h()))}}},/* 12 */
273 | /***/
274 | function(a,b,c){/*istanbul ignore start*/
275 | "use strict";/*istanbul ignore start*/
276 | function d(a){if(Array.isArray(a)){for(var b=0,c=Array(a.length);b0?j(h.lines.slice(-i.context)):[],m-=o.length,n-=o.length)}
282 | // Output our changes
283 | /*istanbul ignore start*/
284 | (g=/*istanbul ignore end*/o).push.apply(/*istanbul ignore start*/g,/*istanbul ignore start*/d(/*istanbul ignore end*/f.map(function(a){return(b.added?"+":"-")+a}))),
285 | // Track the updated file position
286 | b.added?q+=f.length:p+=f.length}else{
287 | // Identical context lines. Track line changes
288 | if(m)
289 | // Close out any changes that have been output (or join overlapping)
290 | if(f.length<=2*i.context&&a=k.length-2&&f.length<=i.context){
297 | // EOF is inside this hunk
298 | var v=/\n$/.test(c),w=/\n$/.test(e);0!=f.length||v?v&&w||o.push("\\ No newline at end of file"):
299 | // special case: old has no eol and no trailing context; no-nl can end up before adds
300 | o.splice(u.oldLines,0,"\\ No newline at end of file")}l.push(u),m=0,n=0,o=[]}p+=f.length,q+=f.length}},s=0;s"):e.removed&&b.push(""),b.push(d(e.value)),e.added?b.push(""):e.removed&&b.push("")}return b.join("")}function d(a){var b=a;return b=b.replace(/&/g,"&"),b=b.replace(//g,">"),b=b.replace(/"/g,""")}b.__esModule=!0,b.convertChangesToXML=c}])});
312 |
--------------------------------------------------------------------------------