mirror of
https://github.com/ganelson/inform.git
synced 2024-06-29 05:24:57 +03:00
Kits now use JSON metadata
This commit is contained in:
parent
97dd0b9eda
commit
b010ef8984
|
@ -1,6 +1,6 @@
|
||||||
# Inform 7
|
# Inform 7
|
||||||
|
|
||||||
v10.1.0-beta+6V19 'Krypton' (1 June 2022)
|
v10.1.0-beta+6V20 'Krypton' (3 June 2022)
|
||||||
|
|
||||||
## About Inform 7
|
## About Inform 7
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
Prerelease: beta
|
Prerelease: beta
|
||||||
Build Date: 1 June 2022
|
Build Date: 3 June 2022
|
||||||
Build Number: 6V19
|
Build Number: 6V20
|
||||||
|
|
|
@ -69,7 +69,7 @@ to specifying |-kit BasicInformKit|.
|
||||||
|
|
||||||
@ Kits have the ability to specify that other kits are automatically added to
|
@ Kits have the ability to specify that other kits are automatically added to
|
||||||
the project in an ITTT, "if-this-then-that", way. As we shall see, every kit
|
the project in an ITTT, "if-this-then-that", way. As we shall see, every kit
|
||||||
contains a file called |kit_metadata.txt| describing its needs. The metadata
|
contains a file called |kit_metadata.json| describing its needs. The metadata
|
||||||
for CommandParserKit includes:
|
for CommandParserKit includes:
|
||||||
= (text)
|
= (text)
|
||||||
dependency: if CommandParserKit then WorldModelKit
|
dependency: if CommandParserKit then WorldModelKit
|
||||||
|
@ -84,7 +84,7 @@ It follows that if WorldModelKit is not present, then BasicInformExtrasKit is
|
||||||
automatically added instead.
|
automatically added instead.
|
||||||
|
|
||||||
@ Kits can also use their metadata to specify that associated extensions should
|
@ Kits can also use their metadata to specify that associated extensions should
|
||||||
automatically be loaded into the project.[1] For example, the |kit_metadata.txt|
|
automatically be loaded into the project.[1] For example, the |kit_metadata.json|
|
||||||
for BasicInformKit includes the lines:
|
for BasicInformKit includes the lines:
|
||||||
= (text)
|
= (text)
|
||||||
extension: Basic Inform by Graham Nelson
|
extension: Basic Inform by Graham Nelson
|
||||||
|
@ -193,7 +193,7 @@ an example of the result.) It is simple because it provides only a |Contents.w|
|
||||||
page and a |Sections| subdirectory -- it has no manual, chapters, figures,
|
page and a |Sections| subdirectory -- it has no manual, chapters, figures,
|
||||||
sounds or other paraphernalia.
|
sounds or other paraphernalia.
|
||||||
|
|
||||||
(*) A file called |kit_metadata.txt| describing the kit, its version and its
|
(*) A file called |kit_metadata.json| describing the kit, its version and its
|
||||||
dependencies.
|
dependencies.
|
||||||
|
|
||||||
(*) Compiled binary Inter files -- but only once the kit has been built. These
|
(*) Compiled binary Inter files -- but only once the kit has been built. These
|
||||||
|
@ -245,7 +245,7 @@ very legible, and it is highly verbose.
|
||||||
|
|
||||||
[2] At some point it may be developed out a little, but there's no great need.
|
[2] At some point it may be developed out a little, but there's no great need.
|
||||||
|
|
||||||
@ The metadata file at |BalloonKit/kit_metadata.txt| is going to be simple:
|
@ The metadata file at |BalloonKit/kit_metadata.json| is going to be simple:
|
||||||
= (text)
|
= (text)
|
||||||
extension: Party Balloons by Joseph-Michel Montgolfier
|
extension: Party Balloons by Joseph-Michel Montgolfier
|
||||||
=
|
=
|
||||||
|
|
11
inbuild/Tests/Zoo/Inter/CastrovalvaKit/kit_metadata.json
Normal file
11
inbuild/Tests/Zoo/Inter/CastrovalvaKit/kit_metadata.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"is": {
|
||||||
|
"type": "kit",
|
||||||
|
"title": "CastrovalvaKit",
|
||||||
|
"version": "2.7.1"
|
||||||
|
},
|
||||||
|
"compatibility": "not for 32-bit",
|
||||||
|
"kit-details": {
|
||||||
|
"has-priority": 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
version: 2.7.1
|
|
||||||
compatibility: not for 32-bit
|
|
||||||
priority: 1
|
|
|
@ -479,9 +479,8 @@ just plain old files.
|
||||||
|
|
||||||
=
|
=
|
||||||
pathname *Supervisor::installed_files(void) {
|
pathname *Supervisor::installed_files(void) {
|
||||||
inbuild_nest *I = Supervisor::internal();
|
if (shared_internal_nest) return shared_internal_nest->location;
|
||||||
if (I == NULL) Errors::fatal("Did not set -internal when calling");
|
return Pathnames::from_text(I"inform7/Internal");
|
||||||
return I->location;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ As noted above, the transient area is used for ephemera such as dynamically
|
@ As noted above, the transient area is used for ephemera such as dynamically
|
||||||
|
|
|
@ -19,6 +19,7 @@ typedef struct inbuild_copy {
|
||||||
struct filename *location_if_file;
|
struct filename *location_if_file;
|
||||||
|
|
||||||
general_pointer metadata; /* the type of which depends on the work's genre */
|
general_pointer metadata; /* the type of which depends on the work's genre */
|
||||||
|
struct JSON_value *metadata_record; /* where read in from a JSON file */
|
||||||
struct build_vertex *vertex; /* head vertex of build graph for this copy */
|
struct build_vertex *vertex; /* head vertex of build graph for this copy */
|
||||||
int source_text_read; /* have we attempted to read Inform source text from this? */
|
int source_text_read; /* have we attempted to read Inform source text from this? */
|
||||||
struct wording source_text; /* the source text we read, if so */
|
struct wording source_text; /* the source text we read, if so */
|
||||||
|
@ -38,6 +39,7 @@ inbuild_copy *Copies::new_p(inbuild_edition *edition) {
|
||||||
copy->location_if_path = NULL;
|
copy->location_if_path = NULL;
|
||||||
copy->location_if_file = NULL;
|
copy->location_if_file = NULL;
|
||||||
copy->metadata = NULL_GENERAL_POINTER;
|
copy->metadata = NULL_GENERAL_POINTER;
|
||||||
|
copy->metadata_record = NULL;
|
||||||
copy->vertex = Graphs::copy_vertex(copy);
|
copy->vertex = Graphs::copy_vertex(copy);
|
||||||
copy->source_text_read = FALSE;
|
copy->source_text_read = FALSE;
|
||||||
copy->source_text = EMPTY_WORDING;
|
copy->source_text = EMPTY_WORDING;
|
||||||
|
|
141
inbuild/supervisor-module/Chapter 2/JSON Metadata.w
Normal file
141
inbuild/supervisor-module/Chapter 2/JSON Metadata.w
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
[JSONMetadata::] JSON Metadata.
|
||||||
|
|
||||||
|
Managing JSON-encoded metadata files for resources such as kits.
|
||||||
|
|
||||||
|
@ Every //inbuild_copy// can optionally contain a pointer to a JSON value called
|
||||||
|
|metadata_record|. The code in this section reads a file of JSON metadata into
|
||||||
|
that record, validating it (a) as syntactically correct JSON, (b) as JSON which
|
||||||
|
matches the Inbuild schema for what copy metadata should look like, and (c) as
|
||||||
|
identifying the copy which it purports to identify.
|
||||||
|
|
||||||
|
In practice, (a) and (b) are delegated to the //foundation: JSON// library.
|
||||||
|
|
||||||
|
=
|
||||||
|
void JSONMetadata::read_metadata_file(inbuild_copy *C, filename *F) {
|
||||||
|
JSON_requirement *req = JSONMetadata::requirements();
|
||||||
|
TEMPORARY_TEXT(contents)
|
||||||
|
TextFiles::read(F, FALSE, "unable to read file of JSON metadata", TRUE,
|
||||||
|
&JSONMetadata::read_metadata_file_helper, NULL, contents);
|
||||||
|
text_file_position tfp = TextFiles::at(F, 1);
|
||||||
|
JSON_value *value = JSON::decode(contents, &tfp);
|
||||||
|
if ((value) && (value->JSON_type == ERROR_JSONTYPE)) {
|
||||||
|
@<Report a syntax error in JSON@>;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
@<Validate the JSON read in@>;
|
||||||
|
}
|
||||||
|
DISCARD_TEXT(contents)
|
||||||
|
C->metadata_record = value;
|
||||||
|
@<Examine the "is" member of the metadata object@>;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSONMetadata::read_metadata_file_helper(text_stream *text, text_file_position *tfp,
|
||||||
|
void *v_state) {
|
||||||
|
text_stream *contents = (text_stream *) v_state;
|
||||||
|
WRITE_TO(contents, "%S\n", text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@<Report a syntax error in JSON@> =
|
||||||
|
TEMPORARY_TEXT(err)
|
||||||
|
WRITE_TO(err, "the metadata contains a syntax error: '%S'", value->if_error);
|
||||||
|
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, err));
|
||||||
|
DISCARD_TEXT(err)
|
||||||
|
|
||||||
|
@<Validate the JSON read in@> =
|
||||||
|
linked_list *validation_errors = NEW_LINKED_LIST(text_stream);
|
||||||
|
if (JSON::validate(value, req, validation_errors) == FALSE) {
|
||||||
|
text_stream *err;
|
||||||
|
LOOP_OVER_LINKED_LIST(err, text_stream, validation_errors) {
|
||||||
|
TEMPORARY_TEXT(msg)
|
||||||
|
WRITE_TO(msg, "the metadata did not validate: '%S'", err);
|
||||||
|
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, msg));
|
||||||
|
DISCARD_TEXT(msg)
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@<Examine the "is" member of the metadata object@> =
|
||||||
|
JSON_value *is = JSON::look_up_object(C->metadata_record, I"is");
|
||||||
|
JSON_value *type = JSON::look_up_object(is, I"type");
|
||||||
|
if (type) @<Make sure the type is correct@>;
|
||||||
|
JSON_value *title = JSON::look_up_object(is, I"title");
|
||||||
|
if (title) @<Make sure the title is correct@>;
|
||||||
|
JSON_value *author = JSON::look_up_object(is, I"author");
|
||||||
|
if (author) @<Make sure the author is correct@>;
|
||||||
|
JSON_value *version = JSON::look_up_object(is, I"version");
|
||||||
|
if (version) @<Read the version number and apply it@>;
|
||||||
|
JSON_value *version_range = JSON::look_up_object(is, I"version-range");
|
||||||
|
if (version_range) @<Forbid the use of a version range@>;
|
||||||
|
|
||||||
|
@ So, for example, if this file is from what we think is a kit, then it needs
|
||||||
|
to say that |is.type| is |"kit"|.
|
||||||
|
|
||||||
|
@<Make sure the type is correct@> =
|
||||||
|
text_stream *type_text = type->if_string;
|
||||||
|
text_stream *required_text = I"<unknown";
|
||||||
|
if (C->edition->work->genre == kit_genre) required_text = I"kit";
|
||||||
|
if (C->edition->work->genre == extension_genre) required_text = I"extension";
|
||||||
|
if (C->edition->work->genre == language_genre) required_text = I"language";
|
||||||
|
if (Str::ne(type_text, required_text)) {
|
||||||
|
TEMPORARY_TEXT(msg)
|
||||||
|
WRITE_TO(msg, "the metadata misidentifies the type as '%S', but it should be '%S'",
|
||||||
|
type_text, required_text);
|
||||||
|
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, msg));
|
||||||
|
DISCARD_TEXT(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
@<Make sure the title is correct@> =
|
||||||
|
if (Str::ne(title->if_string, C->edition->work->title)) {
|
||||||
|
TEMPORARY_TEXT(err)
|
||||||
|
WRITE_TO(err, "the metadata says the title is '%S' when it should be '%S'",
|
||||||
|
title->if_string, C->edition->work->title);
|
||||||
|
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, err));
|
||||||
|
DISCARD_TEXT(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
@<Make sure the author is correct@> =
|
||||||
|
if (Str::ne(author->if_string, C->edition->work->author_name)) {
|
||||||
|
TEMPORARY_TEXT(err)
|
||||||
|
WRITE_TO(err, "the metadata says the author is '%S' when it should be '%S'",
|
||||||
|
author->if_string, C->edition->work->author_name);
|
||||||
|
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, err));
|
||||||
|
DISCARD_TEXT(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ Unlike those tests, here we simply trust the metadata to be correctly supplying
|
||||||
|
a version number.
|
||||||
|
|
||||||
|
@<Read the version number and apply it@> =
|
||||||
|
semantic_version_number V = VersionNumbers::from_text(version->if_string);
|
||||||
|
if (VersionNumbers::is_null(V)) {
|
||||||
|
TEMPORARY_TEXT(err)
|
||||||
|
WRITE_TO(err, "cannot read version number '%S'", version->if_string);
|
||||||
|
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, err));
|
||||||
|
DISCARD_TEXT(err)
|
||||||
|
} else {
|
||||||
|
C->edition->version = VersionNumbers::from_text(version->if_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
@<Forbid the use of a version range@> =
|
||||||
|
TEMPORARY_TEXT(err)
|
||||||
|
WRITE_TO(err, "the metadata should specify an exact version, not a range");
|
||||||
|
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, err));
|
||||||
|
DISCARD_TEXT(err)
|
||||||
|
|
||||||
|
@ The following returns the schema needed for (b); we will load it in from a file
|
||||||
|
in the Inform/Inbuild installation, but will then cache the result so that it
|
||||||
|
loads only once.
|
||||||
|
|
||||||
|
=
|
||||||
|
dictionary *JSON_resource_metadata_requirements = NULL;
|
||||||
|
|
||||||
|
JSON_requirement *JSONMetadata::requirements(void) {
|
||||||
|
if (JSON_resource_metadata_requirements == NULL) {
|
||||||
|
filename *F = InstalledFiles::filename(JSON_REQUIREMENTS_IRES);
|
||||||
|
JSON_resource_metadata_requirements = JSON::read_requirements_file(NULL, F);
|
||||||
|
}
|
||||||
|
JSON_requirement *req =
|
||||||
|
JSON::look_up_requirements(JSON_resource_metadata_requirements, I"resource-metadata");
|
||||||
|
if (req == NULL) internal_error("JSON metadata file did not define <resource-metadata>");
|
||||||
|
return req;
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ Inter code.
|
||||||
|
|
||||||
@h Genre definition.
|
@h Genre definition.
|
||||||
The |kit_genre| can be summarised as follows. Kits consist of directories,
|
The |kit_genre| can be summarised as follows. Kits consist of directories,
|
||||||
containing metadata in |D/kit_metadata.txt|, but which are also valid Inweb
|
containing metadata in |D/kit_metadata.json|, but which are also valid Inweb
|
||||||
webs of Inform 6 source text. They are recognised by having directory names
|
webs of Inform 6 source text. They are recognised by having directory names
|
||||||
ending in |Kit|, and by having a metadata file in place. They are stored in
|
ending in |Kit|, and by having a metadata file in place. They are stored in
|
||||||
nests, in |N/Inter/Title-vVersion|. Their build graphs are quite extensive,
|
nests, in |N/Inter/Title-vVersion|. Their build graphs are quite extensive,
|
||||||
|
@ -91,7 +91,7 @@ void KitManager::claim_as_copy(inbuild_genre *gen, inbuild_copy **C,
|
||||||
}
|
}
|
||||||
|
|
||||||
inbuild_copy *KitManager::claim_folder_as_copy(pathname *P) {
|
inbuild_copy *KitManager::claim_folder_as_copy(pathname *P) {
|
||||||
filename *canary = Filenames::in(P, I"kit_metadata.txt");
|
filename *canary = Filenames::in(P, I"kit_metadata.json");
|
||||||
if (TextFiles::exists(canary))
|
if (TextFiles::exists(canary))
|
||||||
return KitManager::new_copy(Pathnames::directory_name(P), P);
|
return KitManager::new_copy(Pathnames::directory_name(P), P);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -136,7 +136,7 @@ pathname *KitManager::pathname_in_nest(inbuild_nest *N, inbuild_edition *E) {
|
||||||
void KitManager::copy_to_nest(inbuild_genre *gen, inbuild_copy *C, inbuild_nest *N,
|
void KitManager::copy_to_nest(inbuild_genre *gen, inbuild_copy *C, inbuild_nest *N,
|
||||||
int syncing, build_methodology *meth) {
|
int syncing, build_methodology *meth) {
|
||||||
pathname *dest_kit = KitManager::pathname_in_nest(N, C->edition);
|
pathname *dest_kit = KitManager::pathname_in_nest(N, C->edition);
|
||||||
filename *dest_kit_metadata = Filenames::in(dest_kit, I"kit_metadata.txt");
|
filename *dest_kit_metadata = Filenames::in(dest_kit, I"kit_metadata.json");
|
||||||
if (TextFiles::exists(dest_kit_metadata)) {
|
if (TextFiles::exists(dest_kit_metadata)) {
|
||||||
if (syncing == FALSE) { Copies::overwrite_error(C, N); return; }
|
if (syncing == FALSE) { Copies::overwrite_error(C, N); return; }
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -70,61 +70,108 @@ void Kits::scan(inbuild_copy *C) {
|
||||||
K->defines_Main = FALSE;
|
K->defines_Main = FALSE;
|
||||||
K->supports_nl = FALSE;
|
K->supports_nl = FALSE;
|
||||||
|
|
||||||
filename *F = Filenames::in(C->location_if_path, I"kit_metadata.txt");
|
filename *F = Filenames::in(C->location_if_path, I"kit_metadata.json");
|
||||||
TextFiles::read(F, FALSE,
|
JSONMetadata::read_metadata_file(C, F);
|
||||||
NULL, FALSE, Kits::read_metadata, NULL, (void *) C);
|
|
||||||
|
if (C->metadata_record) @<Extract what we need@>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ The following reads line by line through the |kit_metadata.txt| file:
|
@<Extract what we need@> =
|
||||||
|
JSON_value *compatibility = JSON::look_up_object(C->metadata_record, I"compatibility");
|
||||||
=
|
if (compatibility) @<Add compatibility@>;
|
||||||
void Kits::read_metadata(text_stream *text, text_file_position *tfp, void *state) {
|
JSON_value *activate = JSON::look_up_object(C->metadata_record, I"activates");
|
||||||
inbuild_copy *C = (inbuild_copy *) state;
|
if (activate) {
|
||||||
inform_kit *K = KitManager::from_copy(C);
|
JSON_value *E;
|
||||||
match_results mr = Regexp::create_mr();
|
LOOP_OVER_LINKED_LIST(E, JSON_value, activate->if_list)
|
||||||
if ((Str::is_whitespace(text)) || (Regexp::match(&mr, text, L" *#%c*"))) {
|
Kits::activation(K, E->if_string, TRUE);
|
||||||
;
|
}
|
||||||
} else if (Regexp::match(&mr, text, L"version: (%C+)"))
|
JSON_value *deactivate = JSON::look_up_object(C->metadata_record, I"deactivates");
|
||||||
C->edition->version = VersionNumbers::from_text(mr.exp[0]);
|
if (deactivate) {
|
||||||
else if (Regexp::match(&mr, text, L"compatibility: (%c+)")) @<Add compatibility@>
|
JSON_value *E;
|
||||||
else if (Regexp::match(&mr, text, L"defines Main: yes")) K->defines_Main = TRUE;
|
LOOP_OVER_LINKED_LIST(E, JSON_value, deactivate->if_list)
|
||||||
else if (Regexp::match(&mr, text, L"defines Main: no")) K->defines_Main = FALSE;
|
Kits::activation(K, E->if_string, FALSE);
|
||||||
else if (Regexp::match(&mr, text, L"natural language: yes")) K->supports_nl = TRUE;
|
}
|
||||||
else if (Regexp::match(&mr, text, L"natural language: no")) K->supports_nl = FALSE;
|
JSON_value *kit_details = JSON::look_up_object(C->metadata_record, I"kit-details");
|
||||||
else if (Regexp::match(&mr, text, L"insert: (%c*)")) @<Add early source@>
|
if (kit_details) {
|
||||||
else if (Regexp::match(&mr, text, L"priority: (%d*)"))
|
JSON_value *priority = JSON::look_up_object(kit_details, I"has-priority");
|
||||||
K->priority = Str::atoi(mr.exp[0], 0);
|
if (priority) K->priority = priority->if_integer;
|
||||||
else if (Regexp::match(&mr, text, L"kinds: (%C+)"))
|
JSON_value *defines_Main = JSON::look_up_object(kit_details, I"defines-Main");
|
||||||
ADD_TO_LINKED_LIST(Str::duplicate(mr.exp[0]), text_stream, K->kind_definitions);
|
if (defines_Main) K->defines_Main = defines_Main->if_boolean;
|
||||||
else if (Regexp::match(&mr, text, L"extension: version (%c+?) of (%c+) by (%c+)"))
|
JSON_value *is_language_kit = JSON::look_up_object(kit_details, I"is-language-kit");
|
||||||
@<Add versioned extension@>
|
if (is_language_kit) K->supports_nl = is_language_kit->if_boolean;
|
||||||
else if (Regexp::match(&mr, text, L"extension: (%c+) by (%c+)"))
|
JSON_value *index = JSON::look_up_object(kit_details, I"indexes-with-structure");
|
||||||
@<Add unversioned extension@>
|
if (index) K->index_structure = index->if_string;
|
||||||
else if (Regexp::match(&mr, text, L"activate: (%c+)"))
|
JSON_value *kinds = JSON::look_up_object(kit_details, I"provides-kinds");
|
||||||
Kits::activation(K, mr.exp[0], TRUE);
|
if (kinds) {
|
||||||
else if (Regexp::match(&mr, text, L"deactivate: (%c+)"))
|
JSON_value *E;
|
||||||
Kits::activation(K, mr.exp[0], FALSE);
|
LOOP_OVER_LINKED_LIST(E, JSON_value, kinds->if_list)
|
||||||
else if (Regexp::match(&mr, text, L"dependency: if (%C+) then (%C+)"))
|
ADD_TO_LINKED_LIST(E->if_string, text_stream, K->kind_definitions);
|
||||||
Kits::dependency(K, mr.exp[0], TRUE, mr.exp[1]);
|
}
|
||||||
else if (Regexp::match(&mr, text, L"dependency: if not (%C+) then (%C+)"))
|
}
|
||||||
Kits::dependency(K, mr.exp[0], FALSE, mr.exp[1]);
|
JSON_value *dependencies = JSON::look_up_object(C->metadata_record, I"needs");
|
||||||
else if (Regexp::match(&mr, text, L"index from: (%c*)"))
|
if (dependencies) {
|
||||||
K->index_structure = Str::duplicate(mr.exp[0]);
|
JSON_value *E;
|
||||||
else {
|
LOOP_OVER_LINKED_LIST(E, JSON_value, dependencies->if_list) {
|
||||||
TEMPORARY_TEXT(err)
|
int loaded = TRUE;
|
||||||
WRITE_TO(err, "unreadable instruction '%S'", text);
|
JSON_value *if_clause = JSON::look_up_object(E, I"if");
|
||||||
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, err));
|
JSON_value *unless_clause = JSON::look_up_object(E, I"unless");
|
||||||
DISCARD_TEXT(err)
|
if ((if_clause) && (unless_clause)) {
|
||||||
|
TEMPORARY_TEXT(err)
|
||||||
|
WRITE_TO(err, "cannot give both 'if' and 'unless' in same requirement");
|
||||||
|
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, err));
|
||||||
|
DISCARD_TEXT(err)
|
||||||
|
}
|
||||||
|
if (unless_clause) {
|
||||||
|
if_clause = unless_clause; loaded = FALSE;
|
||||||
|
}
|
||||||
|
JSON_value *then_clause = JSON::look_up_object(E, I"need");
|
||||||
|
if (then_clause) {
|
||||||
|
JSON_value *type = JSON::look_up_object(then_clause, I"type");
|
||||||
|
JSON_value *title = JSON::look_up_object(then_clause, I"title");
|
||||||
|
JSON_value *author = JSON::look_up_object(then_clause, I"author");
|
||||||
|
JSON_value *then_version = JSON::look_up_object(then_clause, I"version");
|
||||||
|
if (Str::eq(type->if_string, I"extension")) {
|
||||||
|
if (if_clause) {
|
||||||
|
TEMPORARY_TEXT(err)
|
||||||
|
WRITE_TO(err, "a kit can only have an extension as a dependency unconditionally");
|
||||||
|
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, err));
|
||||||
|
DISCARD_TEXT(err)
|
||||||
|
}
|
||||||
|
text_stream *extension_title = title->if_string;
|
||||||
|
text_stream *extension_author = author?(author->if_string):NULL;
|
||||||
|
if (then_version) @<Add versioned extension@>
|
||||||
|
else @<Add unversioned extension@>;
|
||||||
|
} else if (Str::eq(type->if_string, I"kit")) {
|
||||||
|
text_stream *if_kit = C->edition->work->title;
|
||||||
|
if (if_clause) {
|
||||||
|
JSON_value *if_type = JSON::look_up_object(if_clause, I"type");
|
||||||
|
if (Str::eq(if_type->if_string, I"kit") == FALSE) {
|
||||||
|
TEMPORARY_TEXT(err)
|
||||||
|
WRITE_TO(err, "a kit dependency can only be conditional on other kits");
|
||||||
|
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, err));
|
||||||
|
DISCARD_TEXT(err)
|
||||||
|
} else {
|
||||||
|
JSON_value *if_title = JSON::look_up_object(if_clause, I"title");
|
||||||
|
if (if_title) if_kit = if_title->if_string; /* a line for IF fans */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Kits::dependency(K, if_kit, loaded, title->if_string);
|
||||||
|
} else {
|
||||||
|
TEMPORARY_TEXT(err)
|
||||||
|
WRITE_TO(err, "a kit can only have extensions and kits as dependencies");
|
||||||
|
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, err));
|
||||||
|
DISCARD_TEXT(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Regexp::dispose_of(&mr);
|
|
||||||
}
|
|
||||||
|
|
||||||
@<Add compatibility@> =
|
@<Add compatibility@> =
|
||||||
compatibility_specification *CS = Compatibility::from_text(mr.exp[0]);
|
compatibility_specification *CS = Compatibility::from_text(compatibility->if_string);
|
||||||
if (CS) C->edition->compatibility = CS;
|
if (CS) C->edition->compatibility = CS;
|
||||||
else {
|
else {
|
||||||
TEMPORARY_TEXT(err)
|
TEMPORARY_TEXT(err)
|
||||||
WRITE_TO(err, "cannot read compatibility '%S'", mr.exp[0]);
|
WRITE_TO(err, "cannot read compatibility '%S'", compatibility->if_string);
|
||||||
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, err));
|
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, err));
|
||||||
DISCARD_TEXT(err)
|
DISCARD_TEXT(err)
|
||||||
}
|
}
|
||||||
|
@ -134,11 +181,11 @@ void Kits::read_metadata(text_stream *text, text_file_position *tfp, void *state
|
||||||
WRITE_TO(K->early_source, "\n\n");
|
WRITE_TO(K->early_source, "\n\n");
|
||||||
|
|
||||||
@<Add versioned extension@> =
|
@<Add versioned extension@> =
|
||||||
inbuild_work *work = Works::new(extension_genre, mr.exp[1], mr.exp[2]);
|
inbuild_work *work = Works::new(extension_genre, extension_title, extension_author);
|
||||||
semantic_version_number V = VersionNumbers::from_text(mr.exp[0]);
|
semantic_version_number V = VersionNumbers::from_text(then_version->if_string);
|
||||||
if (VersionNumbers::is_null(V)) {
|
if (VersionNumbers::is_null(V)) {
|
||||||
TEMPORARY_TEXT(err)
|
TEMPORARY_TEXT(err)
|
||||||
WRITE_TO(err, "cannot read version number '%S'", mr.exp[0]);
|
WRITE_TO(err, "cannot read version number '%S'", then_version->if_string);
|
||||||
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, err));
|
Copies::attach_error(C, CopyErrors::new_T(KIT_MISWORDED_CE, -1, err));
|
||||||
DISCARD_TEXT(err)
|
DISCARD_TEXT(err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -148,7 +195,7 @@ void Kits::read_metadata(text_stream *text, text_file_position *tfp, void *state
|
||||||
}
|
}
|
||||||
|
|
||||||
@<Add unversioned extension@> =
|
@<Add unversioned extension@> =
|
||||||
inbuild_work *work = Works::new(extension_genre, mr.exp[0], mr.exp[1]);
|
inbuild_work *work = Works::new(extension_genre, extension_title, extension_author);
|
||||||
inbuild_requirement *req = Requirements::any_version_of(work);
|
inbuild_requirement *req = Requirements::any_version_of(work);
|
||||||
ADD_TO_LINKED_LIST(req, inbuild_requirement, K->extensions);
|
ADD_TO_LINKED_LIST(req, inbuild_requirement, K->extensions);
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ Chapter 2: Conceptual Framework
|
||||||
Copy Errors
|
Copy Errors
|
||||||
Requirements
|
Requirements
|
||||||
Nests
|
Nests
|
||||||
|
JSON Metadata
|
||||||
|
|
||||||
Chapter 3: Incremental Builds
|
Chapter 3: Incremental Builds
|
||||||
Build Graphs
|
Build Graphs
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"is": {
|
||||||
|
"type": "kit",
|
||||||
|
"title": "BasicInformExtrasKit",
|
||||||
|
"version": "1"
|
||||||
|
},
|
||||||
|
"kit-details": {
|
||||||
|
"has-priority": 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
priority: 1
|
|
36
inform7/Internal/Inter/BasicInformKit/kit_metadata.json
Normal file
36
inform7/Internal/Inter/BasicInformKit/kit_metadata.json
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"is": {
|
||||||
|
"type": "kit",
|
||||||
|
"title": "BasicInformKit",
|
||||||
|
"version": "1"
|
||||||
|
},
|
||||||
|
"needs": [ {
|
||||||
|
"unless": {
|
||||||
|
"type": "kit",
|
||||||
|
"title": "WorldModelKit"
|
||||||
|
},
|
||||||
|
"need": {
|
||||||
|
"type": "kit",
|
||||||
|
"title": "BasicInformExtrasKit"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"need": {
|
||||||
|
"type": "extension",
|
||||||
|
"title": "Basic Inform",
|
||||||
|
"author": "Graham Nelson"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"need": {
|
||||||
|
"type": "extension",
|
||||||
|
"title": "English Language",
|
||||||
|
"author": "Graham Nelson"
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"activates": [ "glulx external files" ],
|
||||||
|
"kit-details": {
|
||||||
|
"has-priority": 0,
|
||||||
|
"defines-Main": false,
|
||||||
|
"provides-kinds": [ "Macros.neptune", "Protocols.neptune", "Core.neptune", "Punctuation.neptune", "Files.neptune" ],
|
||||||
|
"indexes-with-structure": "Basic.indext"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +0,0 @@
|
||||||
priority: 0
|
|
||||||
extension: Basic Inform by Graham Nelson
|
|
||||||
extension: English Language by Graham Nelson
|
|
||||||
dependency: if not WorldModelKit then BasicInformExtrasKit
|
|
||||||
kinds: Macros.neptune
|
|
||||||
kinds: Protocols.neptune
|
|
||||||
kinds: Core.neptune
|
|
||||||
kinds: Punctuation.neptune
|
|
||||||
kinds: Files.neptune
|
|
||||||
activate: glulx external files
|
|
||||||
defines Main: no
|
|
||||||
index from: Basic.indext
|
|
24
inform7/Internal/Inter/CommandParserKit/kit_metadata.json
Normal file
24
inform7/Internal/Inter/CommandParserKit/kit_metadata.json
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"is": {
|
||||||
|
"type": "kit",
|
||||||
|
"title": "CommandParserKit",
|
||||||
|
"version": "1"
|
||||||
|
},
|
||||||
|
"needs": [ {
|
||||||
|
"need": {
|
||||||
|
"type": "kit",
|
||||||
|
"title": "WorldModelKit"
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
"need": {
|
||||||
|
"type": "extension",
|
||||||
|
"title": "Standard Rules",
|
||||||
|
"author": "Graham Nelson"
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"activates": [ "command" ],
|
||||||
|
"kit-details": {
|
||||||
|
"has-priority": 3,
|
||||||
|
"provides-kinds": [ "Parsing.neptune" ]
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
priority: 3
|
|
||||||
extension: Standard Rules by Graham Nelson
|
|
||||||
dependency: if CommandParserKit then WorldModelKit
|
|
||||||
activate: command
|
|
||||||
kinds: Parsing.neptune
|
|
17
inform7/Internal/Inter/EnglishLanguageKit/kit_metadata.json
Normal file
17
inform7/Internal/Inter/EnglishLanguageKit/kit_metadata.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"is": {
|
||||||
|
"type": "kit",
|
||||||
|
"title": "EnglishLanguageKit",
|
||||||
|
"version": "1"
|
||||||
|
},
|
||||||
|
"needs": [ {
|
||||||
|
"need": {
|
||||||
|
"type": "extension",
|
||||||
|
"title": "English Language",
|
||||||
|
"author": "Graham Nelson"
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"kit-details": {
|
||||||
|
"has-priority": 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
priority: 1
|
|
||||||
extension: English Language by Graham Nelson
|
|
||||||
natural language: yes
|
|
21
inform7/Internal/Inter/WorldModelKit/kit_metadata.json
Normal file
21
inform7/Internal/Inter/WorldModelKit/kit_metadata.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"is": {
|
||||||
|
"type": "kit",
|
||||||
|
"title": "WorldModelKit",
|
||||||
|
"version": "1"
|
||||||
|
},
|
||||||
|
"needs": [ {
|
||||||
|
"need": {
|
||||||
|
"type": "extension",
|
||||||
|
"title": "Standard Rules",
|
||||||
|
"author": "Graham Nelson"
|
||||||
|
}
|
||||||
|
} ],
|
||||||
|
"activates": [ "interactive fiction", "multimedia" ],
|
||||||
|
"kit-details": {
|
||||||
|
"has-priority": 2,
|
||||||
|
"defines-Main": true,
|
||||||
|
"provides-kinds": [ "Actions.neptune", "Times.neptune", "Scenes.neptune", "Figures.neptune", "Sounds.neptune" ],
|
||||||
|
"indexes-with-structure": "Standard.indext"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
priority: 2
|
|
||||||
extension: Standard Rules by Graham Nelson
|
|
||||||
kinds: Actions.neptune
|
|
||||||
kinds: Times.neptune
|
|
||||||
kinds: Scenes.neptune
|
|
||||||
kinds: Figures.neptune
|
|
||||||
kinds: Sounds.neptune
|
|
||||||
activate: interactive fiction
|
|
||||||
activate: multimedia
|
|
||||||
defines Main: yes
|
|
||||||
index from: Standard.indext
|
|
35
inform7/Internal/Miscellany/metadata.jsonr
Normal file
35
inform7/Internal/Miscellany/metadata.jsonr
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<resource> ::= {
|
||||||
|
"type": ( "kit" | "extension" | "language" ),
|
||||||
|
"title": string,
|
||||||
|
?"author": string,
|
||||||
|
?"version": string,
|
||||||
|
?"version-range": string
|
||||||
|
}
|
||||||
|
|
||||||
|
<kit-metadata> ::= {
|
||||||
|
?"has-priority": number,
|
||||||
|
?"provides-kinds": [ string* ],
|
||||||
|
?"defines-Main": boolean,
|
||||||
|
?"indexes-with-structure": string
|
||||||
|
}
|
||||||
|
|
||||||
|
<extension-metadata> ::= {
|
||||||
|
}
|
||||||
|
|
||||||
|
<language-metadata> ::= {
|
||||||
|
}
|
||||||
|
|
||||||
|
<resource-metadata> ::= {
|
||||||
|
"is": <resource>,
|
||||||
|
?"compatibility": string,
|
||||||
|
?"activates": [ string* ],
|
||||||
|
?"deactivates": [ string* ],
|
||||||
|
?"needs": [ {
|
||||||
|
?"if": <resource>,
|
||||||
|
?"unless": <resource>,
|
||||||
|
"need": <resource>
|
||||||
|
}* ],
|
||||||
|
?"kit-details": <kit-metadata>,
|
||||||
|
?"extension-details": <extension-metadata>,
|
||||||
|
?"language-details": <language-metadata>
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ but they're just plain old files, and are not managed by Inbuild as "copies".
|
||||||
@e CSS_SET_BY_PLATFORM_IRES
|
@e CSS_SET_BY_PLATFORM_IRES
|
||||||
@e CSS_FOR_STANDARD_PAGES_IRES
|
@e CSS_FOR_STANDARD_PAGES_IRES
|
||||||
@e EXTENSION_DOCUMENTATION_MODEL_IRES
|
@e EXTENSION_DOCUMENTATION_MODEL_IRES
|
||||||
|
@e JSON_REQUIREMENTS_IRES
|
||||||
|
|
||||||
=
|
=
|
||||||
filename *InstalledFiles::filename(int ires) {
|
filename *InstalledFiles::filename(int ires) {
|
||||||
|
@ -38,6 +39,8 @@ filename *InstalledFiles::filename(int ires) {
|
||||||
return Filenames::in(misc, I"DefaultCover.jpg");
|
return Filenames::in(misc, I"DefaultCover.jpg");
|
||||||
case SMALL_DEFAULT_COVER_ART_IRES:
|
case SMALL_DEFAULT_COVER_ART_IRES:
|
||||||
return Filenames::in(misc, I"Small Cover.jpg");
|
return Filenames::in(misc, I"Small Cover.jpg");
|
||||||
|
case JSON_REQUIREMENTS_IRES:
|
||||||
|
return Filenames::in(misc, I"metadata.jsonr");
|
||||||
|
|
||||||
case CBLORB_REPORT_MODEL_IRES:
|
case CBLORB_REPORT_MODEL_IRES:
|
||||||
return InstalledFiles::varied_by_platform(models, I"CblorbModel.html");
|
return InstalledFiles::varied_by_platform(models, I"CblorbModel.html");
|
||||||
|
|
Loading…
Reference in a new issue