Skip to content

Commit

Permalink
move utilities to a separate source dir.
Browse files Browse the repository at this point in the history
  - move pure artifact generation out of tests
  • Loading branch information
dslmeinte committed Aug 29, 2023
1 parent 1b7a96c commit 8f6ba92
Show file tree
Hide file tree
Showing 27 changed files with 163 additions and 128 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,12 @@ The following is a list of links to potential starting points:
* [Models](models/) - various models in their serialized formats (the LIonWeb JSON format, or Ecore XML); see the [specific README](models/README.md).
* [Schemas](schemas/) - various JSON Schema files for validating models serialized in the LIonWeb JSON format against; see the [specific README](schemas/README.md).
* [Source](src/) - all TypeScript source to be exported as part of the NPM/Deno package.
* [Command-line interface](src-cli/) - TypeScript source that implements a single-entrypoint CLI for utilities around the LIonCore functionality, such as: JSON Schema and diagram generation, textual syntax, extractors for the deserialization format, Ecore import, etc.
* [Scripts](src-build) - a `build-npm.ts` Deno script to package the source as an NPM package using [`dnt`](https://github.com/denoland/dnt).
* [Command-line interface](src-cli/) - TypeScript source that implements a single-entrypoint CLI for utilities around the LIonCore functionality, such as: JSON Schema and diagram generation, textual syntax, extractors for the deserialization format, Ecore import, etc.
* [Test sources](src-test/) - all TypeScript sources with/for (unit) tests.
Tests are located in files with names ending with `.test.ts`.
Any such file tests the file under the same path in `src/` that has the same name minus the `.test` part.
* [Utilities](src-utils/) - TypeScript source that implements utilities around LIonCore, but should not go in the NPM package.

**TODO** elaborate

Expand Down Expand Up @@ -96,7 +97,7 @@ The following are considerations or concerns that bubbled up during implementati
Run

```shell
deno run -A src-build/build-npm.ts
deno task build-npm
```

This will create a package in the `npm` directory.
Expand Down
15 changes: 9 additions & 6 deletions deno.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
{
"tasks": {
"run-tests": "deno test --allow-read --allow-write src-test/",
"watch-tests": "deno test --watch --allow-write --allow-read src-test/",
"lint": "deno lint src/ src-test/ src-cli/",
"lock-deps": "deno cache --reload --lock=deno.lock --lock-write src/deps.ts src-cli/deps.ts src-build/build-npm.ts src-test/deps.ts",
"compile-cli": "deno compile --allow-read --allow-write src-cli/lioncore-cli.ts && mv lioncore-cli lib/"
"generate-artifacts": "deno run --allow-write src-build/generate-artifacts.ts",
"run-tests": "deno task generate-artifacts && deno test --allow-read --allow-write src-test/",
"watch-tests": "deno task generate-artifacts && deno test --watch --allow-write --allow-read src-test/",
"lint": "deno lint src/ src-build/ src-cli/ src-test/ src-utils/",
"lock-deps": "deno cache --reload --lock=deno.lock --lock-write src/deps.ts src-build/build-npm.ts src-cli/deps.ts src-test/deps.ts src-utils/deps.ts",
"compile-cli": "deno compile --allow-read --allow-write src-cli/lioncore-cli.ts && mv lioncore-cli lib/",
"build-npm": "deno run -A src-build/build-npm.ts"
},
"lint": {
"include": [
"src/",
"src-build/",
"src-cli/",
"src-test/"
"src-test/",
"src-utils/"
],
"rules": {
"tags": [
Expand Down
1 change: 0 additions & 1 deletion deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src-build/build-npm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ await emptyDir("./npm/script/src-test/m3")
await emptyDir("./npm/esm/src-test/m3/ecore")
await emptyDir("./npm/script/src-test/m3/ecore")

await copy("schemas", "npm/esm/schemas", { overwrite: true });
await copy("schemas", "npm/script/schemas", { overwrite: true });
await copy("schemas", "npm/esm/schemas", { overwrite: true })
await copy("schemas", "npm/script/schemas", { overwrite: true })
await copy("diagrams", "npm/esm/diagrams", { overwrite: true })
await copy("diagrams", "npm/script/diagrams", { overwrite: true })
await copy("models", "npm/esm/models", { overwrite: true })
Expand Down
53 changes: 53 additions & 0 deletions src-build/generate-artifacts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {serializeNodes} from "../src/serializer.ts"
import {lioncoreBuiltins} from "../src/m3/builtins.ts"
import {lioncore} from "../src/m3/lioncore.ts"
import {serializeLanguage} from "../src/m3/serializer.ts"
import {Language} from "../src/m3/types.ts"
import {libraryLanguage} from "../src-test/m3/library-language.ts"
import {libraryModel, libraryModelApi} from "../src-test/library.ts"
import {generatePlantUmlForLanguage} from "../src-utils/m3/diagrams/PlantUML-generator.ts"
import {generateMermaidForLanguage} from "../src-utils/m3/diagrams/Mermaid-generator.ts"
import {schemaFor} from "../src-utils/m3/schema-generator.ts"
import {writeJsonAsFile} from "../src-utils/json.ts"
import {serializedLioncorePath} from "./paths.ts"


await writeJsonAsFile("models/meta/builtins.json", serializeLanguage(lioncoreBuiltins))
console.log(`serialized LIonCore-builtins`)
await writeJsonAsFile(serializedLioncorePath, serializeLanguage(lioncore))
console.log(`serialized LIonCore-M3`)

await Deno.writeTextFileSync("diagrams/metametamodel-gen.puml", generatePlantUmlForLanguage(lioncore))
await Deno.writeTextFileSync("diagrams/metametamodel-gen.md", generateMermaidForLanguage(lioncore))
console.log(`generated diagrams for LIonCore M3`)


await writeJsonAsFile("models/meta/library.json", serializeLanguage(libraryLanguage))
console.log(`serialized Library M2`)

await Deno.writeTextFileSync("diagrams/library-gen.puml", generatePlantUmlForLanguage(libraryLanguage))
await Deno.writeTextFileSync("diagrams/library-gen.md", generateMermaidForLanguage(libraryLanguage))
console.log(`generated diagrams for Library M2`)

await writeJsonAsFile("models/instance/library.json", serializeNodes(libraryModel, libraryModelApi))
console.log(`serialized library M1`)


const persistSchemaFor = async (language: Language) => {
const schema = schemaFor(language)
const schemaName = language.name.toLowerCase()
await writeJsonAsFile(`schemas/${schemaName}.serialization.schema.json`, schema)
}

await persistSchemaFor(lioncore)
await persistSchemaFor(libraryLanguage)

/*
* TODO for JSON Schema validation:
1. meta-validate generic serialization schema separately
2. meta-validate all generated serialization schemas
3. validate all serializations (persisted → separately; in-test → on-the-fly)
*/

2 changes: 2 additions & 0 deletions src-build/paths.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const serializedLioncorePath = "models/meta/lioncore.json"

7 changes: 5 additions & 2 deletions src-cli/deps.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import {parse} from "https://deno.land/[email protected]/flags/mod.ts"
// for src-cli/serialization-extractor.ts:
import {extname} from "https://deno.land/[email protected]/path/mod.ts"

export {parse as parseCliFlags, extname as extensionOfPath}

export {
extname as extensionOfPath
}

20 changes: 19 additions & 1 deletion src-cli/lioncore-cli.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { extractFromSerialization } from "./serialization-extractor.ts"
import {extractFromSerialization} from "./serialization-extractor.ts"
import {diagramFromSerialization} from "./m3/diagram-generator.ts"


const main = (args: string[])=> {
Expand All @@ -18,6 +19,18 @@ Commands are:

const command = args[0]
switch (command) {

case "diagram": {
if (args.length === 1) {
console.log(
`The diagram command generates a PlantUML and Mermaid diagram for the language that the given paths point to.`
)
} else {
args.slice(1).forEach(diagramFromSerialization)
}
return
}

case "extract": {
if (args.length === 1) {
console.log(
Expand All @@ -29,10 +42,15 @@ If the chunk is the serialization of a LIonCore Language/M2, then a textual rend
}
return
}

// TODO schema, Ecore import

default: {
console.error(`command "${command}" is not recognized`)
}
}

}

main(Deno.args)

19 changes: 19 additions & 0 deletions src-cli/m3/diagram-generator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {extensionOfPath} from "../deps.ts"
import {deserializeLanguage} from "../../src/m3/deserializer.ts"
import {generatePlantUmlForLanguage} from "../../src-utils/m3/diagrams/PlantUML-generator.ts"
import {generateMermaidForLanguage} from "../../src-utils/m3/diagrams/Mermaid-generator.ts"


export const diagramFromSerialization = async (path: string) => {
try {
const json = JSON.parse(await Deno.readTextFile(path))
const extlessPath = path.substring(0, path.length - extensionOfPath(path).length)
const language = deserializeLanguage(json)
await Deno.writeTextFileSync(extlessPath + ".puml", generatePlantUmlForLanguage(language))
await Deno.writeTextFileSync(extlessPath + ".md", generateMermaidForLanguage(language))
console.log(`generated diagrams: "${path}" -> "${extlessPath}"`)
} catch (_) {
console.error(`"${path}" is not a valid JSON file`)
}
}

6 changes: 3 additions & 3 deletions src-cli/serialization-extractor.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {extensionOfPath} from "./deps.ts"
import {shortenSerialization, sortSerialization} from "./serialization-utils.ts"
import {writeJsonAsFile} from "../src-test/utils/json.ts"
import {asText} from "../src/m3/textual-syntax.ts"
import {shortenSerialization, sortSerialization} from "../src-utils/serialization-utils.ts"
import {writeJsonAsFile} from "../src-utils/json.ts"
import {deserializeLanguage} from "../src/m3/deserializer.ts"
import {lioncoreQName} from "../src/m3/lioncore.ts"
import {asText} from "../src/m3/textual-syntax.ts"


const isRecord = (json: unknown): json is Record<string, unknown> =>
Expand Down
4 changes: 1 addition & 3 deletions src-test/library.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {assertEquals} from "./deps.ts"
import {writeJsonAsFile} from "./utils/json.ts"
import {undefinedValuesDeletedFrom} from "./utils/test-helpers.ts"
import {serializeNodes} from "../src/serializer.ts"
import {deserializeModel} from "../src/deserializer.ts"
Expand All @@ -11,9 +10,8 @@ import {libraryLanguage} from "./m3/library-language.ts"

Deno.test("Library test model", async (tctx) => {

await tctx.step("[de-]serialize example library", async () => {
await tctx.step("[de-]serialize example library", () => {
const serialization = serializeNodes(libraryModel, libraryModelApi)
await writeJsonAsFile("models/instance/library.json", serialization)
const deserialization = deserializeModel(undefinedValuesDeletedFrom(serialization), libraryModelApi, libraryLanguage, [])
assertEquals(deserialization, libraryModel)
})
Expand Down
8 changes: 0 additions & 8 deletions src-test/m3/builtins.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
import {assertEquals} from "../deps.ts"
import {lioncoreBuiltins} from "../../src/m3/builtins.ts"
import {serializeLanguage} from "../../src/m3/serializer.ts"
import {checkReferences} from "../../src/m3/reference-checker.ts"
import {issuesLanguage} from "../../src/m3/constraints.ts"
import {writeJsonAsFile} from "../utils/json.ts"
import {logIssues, logUnresolvedReferences} from "../utils/test-helpers.ts"


Deno.test("primitive types built-in to LIonCore", async (tctx) => {

await tctx.step("serialize it (no assertions)", async () => {
const serialization = serializeLanguage(lioncoreBuiltins)
await writeJsonAsFile("models/meta/builtins.json", serialization)
})


await tctx.step("check for unresolved references", () => {
const unresolvedReferences = checkReferences(lioncoreBuiltins)
logUnresolvedReferences(unresolvedReferences)
Expand Down
12 changes: 6 additions & 6 deletions src-test/m3/ecore/importer.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {assertEquals, parse} from "../../deps.ts"
import {asLIonCoreLanguage} from "../../../src/m3/ecore/importer.ts"
import {asLIonCoreLanguage} from "../../../src-utils/m3/ecore/importer.ts"
import {serializeLanguage} from "../../../src/m3/serializer.ts"
import {EcoreXml} from "../../../src/m3/ecore/types.ts"
import {EcoreXml} from "../../../src-utils/m3/ecore/types.ts"
import {issuesLanguage} from "../../../src/m3/constraints.ts"
import {checkReferences} from "../../../src/m3/reference-checker.ts"
import {generatePlantUmlForMetamodel} from "../../../src/m3/diagrams/PlantUML-generator.ts"
import {generateMermaidForMetamodel} from "../../../src/m3/diagrams/Mermaid-generator.ts"
import {generatePlantUmlForLanguage} from "../../../src-utils/m3/diagrams/PlantUML-generator.ts"
import {generateMermaidForLanguage} from "../../../src-utils/m3/diagrams/Mermaid-generator.ts"
import {logIssues, logUnresolvedReferences, undefinedValuesDeletedFrom} from "../../utils/test-helpers.ts"
import {libraryLanguage} from "../library-language.ts"

Expand All @@ -32,8 +32,8 @@ Deno.test("Ecore importer", async (tctx) => {
assertEquals(issues, [])
const serialization = serializeLanguage(language)
assertEquals(undefinedValuesDeletedFrom(serialization), undefinedValuesDeletedFrom(serializeLanguage(libraryLanguage)))
assertEquals(generatePlantUmlForMetamodel(language), generatePlantUmlForMetamodel(libraryLanguage))
assertEquals(generateMermaidForMetamodel(language), generateMermaidForMetamodel(libraryLanguage))
assertEquals(generatePlantUmlForLanguage(language), generatePlantUmlForLanguage(libraryLanguage))
assertEquals(generateMermaidForLanguage(language), generateMermaidForLanguage(libraryLanguage))
})

})
Expand Down
13 changes: 1 addition & 12 deletions src-test/m3/library.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import {assertEquals} from "../deps.ts"
import {libraryLanguage} from "./library-language.ts"
import {generatePlantUmlForMetamodel} from "../../src/m3/diagrams/PlantUML-generator.ts"
import {generateMermaidForMetamodel} from "../../src/m3/diagrams/Mermaid-generator.ts"
import {serializeLanguage} from "../../src/m3/serializer.ts"
import {deserializeLanguage} from "../../src/m3/deserializer.ts"
import {lioncoreBuiltins} from "../../src/m3/builtins.ts"
import {writeJsonAsFile} from "../utils/json.ts"
import {undefinedValuesDeletedFrom} from "../utils/test-helpers.ts"


Expand All @@ -16,16 +13,8 @@ Deno.test("Library test metamodel", async (tctx) => {
assertEquals(libraryLanguage.dependsOn, [])
})

await tctx.step("generate diagrams (no assertions)", async () => {
const plantUmldiagramText = generatePlantUmlForMetamodel(libraryLanguage)
await Deno.writeTextFileSync("diagrams/library-gen.puml", plantUmldiagramText)
const mermaidDiagramText = generateMermaidForMetamodel(libraryLanguage)
await Deno.writeTextFileSync("diagrams/library-gen.md", mermaidDiagramText)
})

await tctx.step("serialize it", async () => {
await tctx.step("serialize it", () => {
const serialization = serializeLanguage(libraryLanguage)
await writeJsonAsFile("models/meta/library.json", serialization)
const deserialization = deserializeLanguage(undefinedValuesDeletedFrom(serialization))
assertEquals(deserialization, libraryLanguage)
})
Expand Down
21 changes: 4 additions & 17 deletions src-test/m3/meta-circularity.test.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
import {assertEquals} from "../deps.ts"
import {lioncore} from "../../src/m3/lioncore.ts"
import {generateMermaidForMetamodel} from "../../src/m3/diagrams/Mermaid-generator.ts"
import {generatePlantUmlForMetamodel} from "../../src/m3/diagrams/PlantUML-generator.ts"
import {checkReferences} from "../../src/m3/reference-checker.ts"
import {issuesLanguage} from "../../src/m3/constraints.ts"
import {serializeLanguage} from "../../src/m3/serializer.ts"
import {deserializeLanguage} from "../../src/m3/deserializer.ts"
import {readFileAsJson, writeJsonAsFile} from "../utils/json.ts"
import {readFileAsJson} from "../../src-utils/json.ts"
import {SerializationChunk} from "../../src/serialization.ts"
import {logIssues, logUnresolvedReferences} from "../utils/test-helpers.ts"
import {asText} from "../../src/m3/textual-syntax.ts"
import {serializedLioncorePath} from "../../src-build/paths.ts"


Deno.test("meta-circularity (LIonCore)", async (tctx) => {

await tctx.step("generate PlantUML and Mermaid diagrams (no assertions)", async () => {
await Deno.writeTextFileSync("diagrams/metametamodel-gen.puml", generatePlantUmlForMetamodel(lioncore))
await Deno.writeTextFileSync("diagrams/metametamodel-gen.md", generateMermaidForMetamodel(lioncore))
})

await tctx.step("check for unresolved references", () => {
const unresolvedReferences = checkReferences(lioncore)
logUnresolvedReferences(unresolvedReferences)
Expand All @@ -27,24 +20,18 @@ Deno.test("meta-circularity (LIonCore)", async (tctx) => {

await tctx.step("check constraints", () => {
const issues = issuesLanguage(lioncore)
// TODO find out why computing issues is slow for a small language like LIonCore
// TODO find out why computing issues is slow for a small language like LIonCore
logIssues(issues)
assertEquals(issues, [], "number of expected constraint violations -- see above for the issues")
})

const serializedLioncorePath = "models/meta/lioncore.json"
await tctx.step("serialize LIonCore (no assertions)", async () => {
const serialization = serializeLanguage(lioncore)
await writeJsonAsFile(serializedLioncorePath, serialization)
})

await tctx.step("deserialize LIonCore", async () => {
const serialization = await readFileAsJson(serializedLioncorePath) as SerializationChunk
const deserialization = deserializeLanguage(serialization)
assertEquals(asText(deserialization), asText(lioncore))
// assertEquals on object-level is not good enouogh (- maybe because of class JIT'ing?):
// assertEquals(deserialization, lioncore)
// TODO implement proper equality/comparison
// TODO implement proper equality/comparison
})

})
Expand Down
2 changes: 1 addition & 1 deletion src-test/m3/textual-syntax.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {languageWithEnum} from "./language-with-enum.ts"

Deno.test("textual syntax (LIonCore)", async (tctx) => {

await tctx.step("print out language with an enum as text (no assertions)", () => {
await tctx.step("print out language with an enum as text", () => {
assertEquals(
asText(languageWithEnum),
`language language-with-enum
Expand Down
Loading

0 comments on commit 8f6ba92

Please sign in to comment.