diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index 5457567..b034bbe 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -31,8 +31,18 @@ jobs: run: "echo '${{ steps.release.outputs.version }}'" - name: Generate Changelog - run: cog changelog --at ${{ steps.release.outputs.version }} - -t full_hash > GITHUB_CHANGELOG.md + run: + - cog changelog --at ${{ steps.release.outputs.version }} + -t full_hash > GITHUB_CHANGELOG.md + - deno fmt + + - name: Generate tool and lib version + run: sed -i src/versions.ts + "s/\".*\"/\"${{ steps.release.outputs.version }}\"/" + + - name: Update vesion in the Readme documentation + run: sed -i README.md + sed "s/\@[0-9]\.[0-9]\.[0-9]/@${{ steps.release.outputs.version }}/" - name: Upload github release uses: softprops/action-gh-release@v1 diff --git a/.gitignore b/.gitignore index bd25e05..dfc5cde 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ .direnv .coverage -samples/*.csv -samples/*.db -samples/tennis_atp -samples_regenerated.cfwf +samples/initdatas/*.csv +samples/initdatas/*.db +samples/initdatas/tennis_atp +samples/samples_regenerated.cfwf diff --git a/CHANGELOG.md b/CHANGELOG.md index b6eaba8..dae0d34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,43 +1,107 @@ # Changelog -All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines. -- - - +All notable changes to this project will be documented in this file. See +[conventional commits](https://www.conventionalcommits.org/) for commit +guidelines. + +--- + ## [v0.1.0](https://github.com/badele/nix-projects/compare/1f01928591f654b573da7454d513374f0e99f433..v0.1.0) - 2023-11-16 + #### Bug Fixes -- github CI badge - ([c90c1f1](https://github.com/badele/nix-projects/commit/c90c1f1384bf59385d9d9229b7dbc9d271c2d12e)) - [@badele](https://github.com/badele) -- remove some import modules - ([6357632](https://github.com/badele/nix-projects/commit/63576324ed4092053e5c74a9a6fe1cc30d5641ce)) - [@badele](https://github.com/badele) -- update github action (git checkout step) - ([709463c](https://github.com/badele/nix-projects/commit/709463c49ece3f0feee77437626ffc418ec722cf)) - [@badele](https://github.com/badele) + +- github CI badge - + ([c90c1f1](https://github.com/badele/nix-projects/commit/c90c1f1384bf59385d9d9229b7dbc9d271c2d12e)) - + [@badele](https://github.com/badele) +- remove some import modules - + ([6357632](https://github.com/badele/nix-projects/commit/63576324ed4092053e5c74a9a6fe1cc30d5641ce)) - + [@badele](https://github.com/badele) +- update github action (git checkout step) - + ([709463c](https://github.com/badele/nix-projects/commit/709463c49ece3f0feee77437626ffc418ec722cf)) - + [@badele](https://github.com/badele) + #### Continuous Integration -- get the samples datas - ([32607d1](https://github.com/badele/nix-projects/commit/32607d160cd403ac69b9edff97404661ca2eae32)) - [@badele](https://github.com/badele) + +- get the samples datas - + ([32607d1](https://github.com/badele/nix-projects/commit/32607d160cd403ac69b9edff97404661ca2eae32)) - + [@badele](https://github.com/badele) + #### Documentation -- update main readme.md - ([6d7e5f2](https://github.com/badele/nix-projects/commit/6d7e5f2eae6cbaa8c75728e67f2a476a724c2a77)) - [@badele](https://github.com/badele) -- update Readme - ([5233a6b](https://github.com/badele/nix-projects/commit/5233a6bf253f9d6322c5ddf9bccc973ab8a6ce20)) - [@badele](https://github.com/badele) + +- update main readme.md - + ([6d7e5f2](https://github.com/badele/nix-projects/commit/6d7e5f2eae6cbaa8c75728e67f2a476a724c2a77)) - + [@badele](https://github.com/badele) +- update Readme - + ([5233a6b](https://github.com/badele/nix-projects/commit/5233a6bf253f9d6322c5ddf9bccc973ab8a6ce20)) - + [@badele](https://github.com/badele) + #### Features -- create a cfwf class - ([300f1c0](https://github.com/badele/nix-projects/commit/300f1c0118fec07a1a8ebc9c65f898f76677daff)) - [@badele](https://github.com/badele) -- add cfwf writer - ([4ad8a88](https://github.com/badele/nix-projects/commit/4ad8a88dfcf41aa15a6f01b73b8984f8f8ee72ca)) - [@badele](https://github.com/badele) + +- create a cfwf class - + ([300f1c0](https://github.com/badele/nix-projects/commit/300f1c0118fec07a1a8ebc9c65f898f76677daff)) - + [@badele](https://github.com/badele) +- add cfwf writer - + ([4ad8a88](https://github.com/badele/nix-projects/commit/4ad8a88dfcf41aa15a6f01b73b8984f8f8ee72ca)) - + [@badele](https://github.com/badele) + #### Miscellaneous Chores -- **(version)** v0.1.0 - ([ee214bc](https://github.com/badele/nix-projects/commit/ee214bc85eccb62670ca3884d8a56f30b09b5fd6)) - github-actions + +- **(version)** v0.1.0 - + ([ee214bc](https://github.com/badele/nix-projects/commit/ee214bc85eccb62670ca3884d8a56f30b09b5fd6)) - + github-actions + #### Tests -- fix test linter - ([dadef2b](https://github.com/badele/nix-projects/commit/dadef2b4b15b0c73944d1dc348fff28d62a8c521)) - [@badele](https://github.com/badele) -- - - +- fix test linter - + ([dadef2b](https://github.com/badele/nix-projects/commit/dadef2b4b15b0c73944d1dc348fff28d62a8c521)) - + [@badele](https://github.com/badele) + +--- ## [v0.1.0](https://github.com/badele/nix-projects/compare/1f01928591f654b573da7454d513374f0e99f433..v0.1.0) - 2023-11-16 + #### Bug Fixes -- github CI badge - ([c90c1f1](https://github.com/badele/nix-projects/commit/c90c1f1384bf59385d9d9229b7dbc9d271c2d12e)) - [@badele](https://github.com/badele) -- remove some import modules - ([6357632](https://github.com/badele/nix-projects/commit/63576324ed4092053e5c74a9a6fe1cc30d5641ce)) - [@badele](https://github.com/badele) -- update github action (git checkout step) - ([709463c](https://github.com/badele/nix-projects/commit/709463c49ece3f0feee77437626ffc418ec722cf)) - [@badele](https://github.com/badele) + +- github CI badge - + ([c90c1f1](https://github.com/badele/nix-projects/commit/c90c1f1384bf59385d9d9229b7dbc9d271c2d12e)) - + [@badele](https://github.com/badele) +- remove some import modules - + ([6357632](https://github.com/badele/nix-projects/commit/63576324ed4092053e5c74a9a6fe1cc30d5641ce)) - + [@badele](https://github.com/badele) +- update github action (git checkout step) - + ([709463c](https://github.com/badele/nix-projects/commit/709463c49ece3f0feee77437626ffc418ec722cf)) - + [@badele](https://github.com/badele) + #### Continuous Integration -- get the samples datas - ([32607d1](https://github.com/badele/nix-projects/commit/32607d160cd403ac69b9edff97404661ca2eae32)) - [@badele](https://github.com/badele) + +- get the samples datas - + ([32607d1](https://github.com/badele/nix-projects/commit/32607d160cd403ac69b9edff97404661ca2eae32)) - + [@badele](https://github.com/badele) + #### Documentation -- update main readme.md - ([6d7e5f2](https://github.com/badele/nix-projects/commit/6d7e5f2eae6cbaa8c75728e67f2a476a724c2a77)) - [@badele](https://github.com/badele) -- update Readme - ([5233a6b](https://github.com/badele/nix-projects/commit/5233a6bf253f9d6322c5ddf9bccc973ab8a6ce20)) - [@badele](https://github.com/badele) + +- update main readme.md - + ([6d7e5f2](https://github.com/badele/nix-projects/commit/6d7e5f2eae6cbaa8c75728e67f2a476a724c2a77)) - + [@badele](https://github.com/badele) +- update Readme - + ([5233a6b](https://github.com/badele/nix-projects/commit/5233a6bf253f9d6322c5ddf9bccc973ab8a6ce20)) - + [@badele](https://github.com/badele) + #### Features -- create a cfwf class - ([300f1c0](https://github.com/badele/nix-projects/commit/300f1c0118fec07a1a8ebc9c65f898f76677daff)) - [@badele](https://github.com/badele) -- add cfwf writer - ([4ad8a88](https://github.com/badele/nix-projects/commit/4ad8a88dfcf41aa15a6f01b73b8984f8f8ee72ca)) - [@badele](https://github.com/badele) + +- create a cfwf class - + ([300f1c0](https://github.com/badele/nix-projects/commit/300f1c0118fec07a1a8ebc9c65f898f76677daff)) - + [@badele](https://github.com/badele) +- add cfwf writer - + ([4ad8a88](https://github.com/badele/nix-projects/commit/4ad8a88dfcf41aa15a6f01b73b8984f8f8ee72ca)) - + [@badele](https://github.com/badele) + #### Tests -- fix test linter - ([dadef2b](https://github.com/badele/nix-projects/commit/dadef2b4b15b0c73944d1dc348fff28d62a8c521)) - [@badele](https://github.com/badele) -- - - +- fix test linter - + ([dadef2b](https://github.com/badele/nix-projects/commit/dadef2b4b15b0c73944d1dc348fff28d62a8c521)) - + [@badele](https://github.com/badele) + +--- -Changelog generated by [cocogitto](https://github.com/cocogitto/cocogitto). \ No newline at end of file +Changelog generated by [cocogitto](https://github.com/cocogitto/cocogitto). diff --git a/README.md b/README.md index 2cf585e..476bf95 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,8 @@ [![Build status](https://github.com/badele/cfwf/workflows/CI/badge.svg)](https://github.com/badele/cfwf/actions/workflows/CI.yml) [![Code coverage](https://codecov.io/gh/badele/cfwf/branch/main/graph/badge.svg)](https://codecov.io/gh/badele/cfwf) -**cfwf** is a library designed to facilitate the conversion of tables or -dictionaries into a human-readable format compatible with a simple text file -reader. +**cfwf** is a tool and library designed to facilitate the conversion of tables +into a human-readable format compatible with a simple text file reader. ## Project Motivation @@ -25,63 +24,83 @@ tabular data. - **Commentary and Metadata Inclusion:** Posibility to add comments and metadata to the entire CFWF file, also for each table -## Example - -### Code - -```typescript -import { CFWF } from "./mod.ts"; -import { parseCSV } from "./src/utils.ts"; - -const metas: any = { - title: " ATP Tour", - comment: "Here is a list of the best tennis players in the ATP rankings\n\ -from 2012 to 2022, as well as the list of winners of the\n\ -4 major Grand Slam tournaments.", - sources: [ - "https://github.com/JeffSackmann/tennis_atp", - ], -}; - -const samples = new CFWF(metas); - -const players_txt = Deno.readTextFileSync("samples/players.csv"); -const players = parseCSV(players_txt); - -const australian_txt = Deno.readTextFileSync("samples/australian_open.csv"); -const australian = parseCSV(australian_txt); - -samples.addArray( - "players", - "The best players (number of winning matches) beetween 2012-2022 ", - "", - players.columns, - players.values, - { - aligns: ["left", "right", "left", "center", "right", "right", "right"], - sources: "https://github.com/JeffSackmann/tennis_atp", - }, -); - -samples.addArray( - "australian_open", - "Australian Open winners beetween 2012-2022", -"The Australian Open is a tennis tournament held annually at Melbourne Park\n\ -in Melbourne, Victoria, Australia. The tournament is the first of the \n\ -four Grand Slam tennis events held each year.", - ["year", "tourney name", "birth nat", "winner"], - australian.values, - { - aligns: ["right", "left", "center", "center"], - sources: [ - "https://fr.wikipedia.org/wiki/Open_d%27Australie", - "https://github.com/JeffSackmann/tennis_atp", - ], - }, -); +## Installation + +```shell +curl -fsSL https://deno.land/x/install/install.sh | sh +deno install -A -fn cfwf https://deno.land/x/cfwf@0.0.1/mod.ts +cfwf convert -i https://media.githubusercontent.com/media/datablist/sample-csv-files/main/files/people/people-100.csv -o /tmp/people.cfwf +less -S /tmp/people.cfwf ``` -### Result +## Usage + +### Simple file conversion + +```text +Usage: cfwf convert --input --output +Version: 0.0.1 + +Description: + + Convert files + +Options: + + -h, --help - Show this help. + -i, --input - Input filenme (required) + -o, --output - Output filenme (required) + -t, --tablename - Define table name + -s, --subtitle - Define table subtitle + -l, --columns - Columns name (Default: []) + -a, --aligns - Aligns for each columns + -S, --separate - Separate content & metadatas +``` + +```shell +cfwf convert -i https://media.githubusercontent.com/media/datablist/sample-csv-files/main/files/people/people-100.csv -o /tmp/people.cfwf +less -S /tmp/people.cfwf +``` + +### Multiples files conversion + +```shell +cfwf dataset init -c /tmp/config.json + +cfwf dataset set \ +-c /tmp/config.json \ +-t " CSV Samples" \ +-d "$(cat << EOD +This is an example of how to convert a CSV file into a CFWF file. +The data comes from the https://github.com/datablist/sample-csv-files project. +Thanks to the author for providing the example data. +EOD +) +" \ +-m '{ "sources": [ "https://github.com/datablist/sample-csv-files" ]}' + +cfwf table add \ +-c /tmp/config.json \ +-f https://media.githubusercontent.com/media/datablist/sample-csv-files/main/files/people/people-100.csv \ +-t peoples \ +-s "The peoples list" \ +-l "Index,User Id,First Name,Last Name,Sex,Email,Phone,Date of birth,Job Title" \ +-a "right,right,right,left,center,left,left,center,left" \ +-m '{ "sources": [ "https://github.com/datablist/sample-csv-files/tree/main/files/people" ]}' + +cfwf table add \ +-c /tmp/config.json \ +-f https://media.githubusercontent.com/media/datablist/sample-csv-files/main/files/customers/customers-100.csv \ +-t customers \ +-s "The customers list" \ +-l "Index,Customer Id,First Name,Last Name,Company,City,Country,Phone 1,Phone 2,Email,Subscription Date,Website" \ +-a "right,right,right,left,right,left,right,right,left,left,center,left" \ +-m '{ "sources": [ "https://github.com/datablist/sample-csv-files/tree/main/files/customers" ]}' + +cfwf export -c /tmp/config.json -o | less -S +``` + +#### Result ```text ___ _____ ______ _____ @@ -139,7 +158,13 @@ year tourney name birth nat winner ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ``` +## Samples + +You can see more examples in the `samples/samplesscripts/` folder + ## Sample dataset -The samples dataset provided by the -[JeffSackmann ATP tennis project](https://github.com/JeffSackmann/tennis_atp) +The samples dataset provided by : + +- [JeffSackmann ATP tennis project](https://github.com/JeffSackmann/tennis_atp) +- [datablist sample csv files](https://github.com/datablist/sample-csv-files) diff --git a/justfile b/justfile index 2e81ce1..3d07246 100644 --- a/justfile +++ b/justfile @@ -12,7 +12,6 @@ BROWSER := "chromium" # Execute test tasks @test: import-atp generate-samples - deno run -A samples/scripts/generate_samples.ts rm -rf ./.coverage deno test --doc --unstable --allow-all --parallel --coverage=./.coverage --trace-ops @@ -37,10 +36,11 @@ coverage-browse browser="chromium": coverage {{ browser }} ./.coverage/html_cov/index.html @import-atp: - ./samples/scripts/import-atp.sh + ./samples/initdatas/import-atp.sh @generate-samples: - deno run -A samples/scripts/generate_samples.ts + deno run -A samples/samplescripts/generate_samples.ts + samples/samplescripts/generate_samples.sh # Run command interactively, view the result in realtime @view: diff --git a/mod.ts b/mod.ts index db83e44..6ae29bc 100644 --- a/mod.ts +++ b/mod.ts @@ -1,3 +1,310 @@ export * from "./src/cfwf.ts"; -export * from "./src/table.ts"; export * from "./src/types.ts"; + +import { CFWFDataset, NamedArray } from "./src/types.ts"; +import { version } from "./src/version.ts"; +import { + Command, + CompletionsCommand, +} from "https://deno.land/x/cliffy@v1.0.0-rc.3/command/mod.ts"; +import { existsSync } from "https://deno.land/std@0.205.0/fs/exists.ts"; +import * as path from "https://deno.land/std@0.205.0/path/mod.ts"; +import { CFWF } from "./src/cfwf.ts"; +import { getCSVObject, readCSVFile } from "./src/converter.ts"; +import { readTextFile } from "./src/utils.ts"; + +// deno-lint-ignore no-explicit-any +function initDatasetFile(options: any): void { + const cfwf: CFWFDataset = { + dataset: { + metadatas: {}, + }, + tables: {}, + }; + + Deno.writeTextFileSync(options.configname, JSON.stringify(cfwf)); +} + +function readConfig(configname: string): CFWFDataset { + if (existsSync(configname) === false) { + return {}; + } + + return JSON.parse(Deno.readTextFileSync(configname)); +} + +// deno-lint-ignore no-explicit-any +async function exportCFWF(options: any): Promise { + const config = readConfig(options.configname); + + const cfwf = new CFWF(config); + if (options.filename) { + cfwf.saveCFWF(options.filename, options.separate); + } else { + const formated = await cfwf.outputCFWF(false); + console.log(formated.content); + } +} + +// deno-lint-ignore no-explicit-any +function setDatasetProperties(options: any): void { + const cfg: CFWFDataset = readConfig(options.configname) || {}; + const cfwf = new CFWF(cfg); + + let { dataset } = cfg || {}; + let { metadatas } = dataset || {}; + + dataset = dataset || {}; + metadatas = metadatas || {}; + + if (options.title) { + dataset.title = options.title ?? dataset.title; + + metadatas.font = options.font; + metadatas.removetitlelines = options.removetitlelines; + } else if (options.generatedtitle) { + dataset.generatedtitle = options.generatedtitle; + } + + if (options.description) { + dataset.description = options.description; + } + + if (options.metadatas) { + Object.assign(metadatas, JSON.parse(options.metadatas)); + } + + cfwf.setDatasetProperties(dataset); + Deno.writeTextFileSync(options.configname, JSON.stringify(cfwf.config)); +} + +// deno-lint-ignore no-explicit-any +async function convertFile(options: any): Promise { + let inputcapacity = false; + let outputcapacity = false; + + const iext = path.extname(options.input); + const oext = path.extname(options.output); + let namedarray: NamedArray = { + columns: [], + rows: [], + }; + + // Input + switch (iext) { + case ".csv": + namedarray = await readCSVFile(options.input); + inputcapacity = true; + break; + } + + // Output + switch (oext) { + case ".cfwf": + namedarray = await readCSVFile(options.input); + outputcapacity = true; + break; + } + + if (inputcapacity === false) { + throw new Error("Input file format not supported"); + } + + if (outputcapacity === false) { + throw new Error("Output file format not supported"); + } + + const cfwf = new CFWF({}); + + // cfwf.setDatasetProperties({ + // title: options.title, + // description: options.description, + // }); + + const tablename = options.tablename || path.basename(options.input, iext); + cfwf.addTable(tablename, { + columns: namedarray.columns, + rows: namedarray.rows, + metadatas: { + aligns: options.aligns, + sources: [ + options.input, + ], + }, + }); + + cfwf.saveCFWF(options.output, false); +} + +// deno-lint-ignore no-explicit-any +async function addTable(options: any): Promise { + const cfg: CFWFDataset = readConfig(options.configname) || {}; + const cfwf = new CFWF(cfg); + + let { tables } = cfg; + tables = tables || {}; + + if (!options.tablename) { + throw new Error("No table name"); + } + + const table = tables[options.tablename] || { + columns: [], + rows: [], + }; + + table.columns = table.columns || []; + table.rows = table.rows || []; + table.metadatas = table.metadatas || {}; + + if (options.columns) { + table.columns = options.columns; + } + + if (options.filename) { + const content = await readTextFile(options.filename); + const datas = getCSVObject(content); + + if (table.columns && table.columns.length === 0) { + table.columns = datas.columns; + } + table.rows = datas.rows; + } + + if (options.subtitle) { + table.subtitle = options.subtitle; + } + + if (options.description) { + table.description = options.description; + } + + if (options.metadatas) { + Object.assign( + // deno-lint-ignore no-explicit-any + table.metadatas as Record, + JSON.parse(options.metadatas), + ); + } + + if (options.aligns) { + table.metadatas.aligns = options.aligns; + } + + // tables[options.tablename] = table; + + cfwf.addTable(options.tablename, table); + Deno.writeTextFileSync(options.configname, JSON.stringify(cfwf.config)); +} + +if (import.meta.main) { + const cmdconvert = new Command() + .description("Convert files") + .option("-i, --input ", "Input filenme", { + required: true, + }) + .option("-o, --output ", "Output filenme", { + required: true, + }) + .option("-t, --tablename ", "Define table name", {}) + .option("-s, --subtitle ", "Define table subtitle", {}) + .option("-l, --columns ", "Columns name", { default: [] }) + .option("-a, --aligns ", "Aligns for each columns", {}) + .option("-S, --separate", "Separate content & metadatas", {}) + .action((options) => convertFile(options)); + + const cmdtable = new Command() + .description("Configure table") + // Add table + .command("add", "Add table configuration") + .option("-c, --configname ", "Config filenme", { + required: true, + }) + .option("-f, --filename ", "File to be load", { + required: true, + }) + .option("-t, --tablename ", "Define table name", { + required: true, + }) + .option( + "-d, --description ", + "Define table description", + {}, + ) + .option("-s, --subtitle ", "Define table subtitle", {}) + .option("-l, --columns ", "Columns name", { default: [] }) + .option("-a, --aligns ", "Aligns for each columns", { + required: true, + }) + .option( + "-m, --metadatas ", + "Define dataset metadatas (JSON format)", + {}, + ) + .action((options) => addTable(options)); + + const cmddataset = new Command() + .description("Configure dataset") + // Init + .command("init", "Init dataset file") + .option("-c, --configname ", "Config filenme", { + required: true, + }) + .action((options) => initDatasetFile(options)) + // Set + .command("set", "Set dataset properties") + .option("-c, --configname ", "Config filenme", { + required: true, + }) + .option("-f, --font ", "Define title font", {}) + .option("-t, --title ", "Define dataset title", {}) + .option( + "-d, --description ", + "Define dataset description", + ) + .option( + "-g, --generatedtitle ", + "Generated title", + { conflicts: ["title", "font"] }, + ) + .option( + "-m, --metadatas ", + "Define dataset metadatas (JSON format)", + {}, + ) + .action((options) => setDatasetProperties(options)) + // Table + .command("table", cmdtable); + + const cmd = new Command() + .name("cfwf") + .version(version) + .description("CFWF Command line") + .command("completions", new CompletionsCommand()) + .command( + "convert", + cmdconvert, + ) + .command( + "dataset", + cmddataset, + ) + .command("export", "output to stdout the dataset to cfwf format file") + .option("-c, --configname ", "Config filenme", { + required: true, + }) + .option("-o, --output", "output to stdout") + .option("-f, --filename ", "export to filename", { + conflicts: ["output"], + }) + .option("-S, --separate", "Separate content & metadatas", { + conflicts: ["output"], + }) + .action((options) => exportCFWF(options)); + + if (Deno.args.length === 0) { + cmd.showHelp(); + } else { + cmd.parse(Deno.args); + } +} diff --git a/samples.cfwf b/samples/generated_by_sh.cfwf similarity index 85% rename from samples.cfwf rename to samples/generated_by_sh.cfwf index 619d0a3..5658154 100644 --- a/samples.cfwf +++ b/samples/generated_by_sh.cfwf @@ -10,10 +10,10 @@ Here is a list of the best tennis players in the ATP rankings from 2012 to 2022, as well as the list of winners of the 4 major Grand Slam tournaments. - ┈┈┈ + ┄┄┄ players -The best players (number of winning matches) beetween 2012-2022 +The best players (number of winning matches) beetween 2012-2022 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ winner_ioc name_first name_last hand height birth nbwins @@ -31,7 +31,7 @@ RUS Andrey Rublev R 188 1997 13 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ The Australian Open is a tennis tournament held annually at Melbourne Park -in Melbourne, Victoria, Australia. The tournament is the first of the +in Melbourne, Victoria, Australia. The tournament is the first of the four Grand Slam tennis events held each year. australian_open @@ -53,7 +53,7 @@ year tourney name birth nat winner 2012 Australian Open SRB Novak Djokovic ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -The major tennis tournament held over two weeks at the Stade Roland Garros +The major tennis tournament held over two weeks at the Stade Roland Garros in Paris, France, beginning in late May each year. The tournament and venue are named after the French aviator Roland Garros. The French Open is the premier clay court championship in the world and the only Grand Slam tournament @@ -79,7 +79,7 @@ year tourney name birth nat winner ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ The US Open Tennis Championships, commonly called the US Open, is a hardcourt tennis -tournament held annually in Queens, New York. Since 1987, the US Open has been +tournament held annually in Queens, New York. Since 1987, the US Open has been chronologically the fourth and final Grand Slam tournament of the year. us_open @@ -106,7 +106,7 @@ in the world and is regarded by many as the most prestigious. It has been held at the All England Lawn Tennis and Croquet Club in Wimbledon, London, since 1877 wimbledon -wimbledon winners beetween 2012-2022 +Wimbledon winners beetween 2012-2022 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ year tourney name birth nat winner @@ -122,25 +122,3 @@ year tourney name birth nat winner 2013 Wimbledon GBR Andy Murray 2012 Wimbledon SUI Roger Federer ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -_infos_: - font: doom - generated_with: 'Generated with https://github.com/badele/cfwf@0.0.1' - removetitlelines: 2 - sources: ['https://github.com/JeffSackmann/tennis_atp'] - title: ' ATP Tour' -australian_open: - aligns: [right, left, center, center] - sources: ['https://fr.wikipedia.org/wiki/Open_d%27Australie', 'https://github.com/JeffSackmann/tennis_atp'] -players: - aligns: [left, right, left, center, right, right, right] - sources: 'https://github.com/JeffSackmann/tennis_atp' -roland_garros: - aligns: [right, left, center, center] - sources: ['https://fr.wikipedia.org/wiki/Internationaux_de_France_de_tennis', 'https://github.com/JeffSackmann/tennis_atp'] -us_open: - aligns: [right, left, center, center] - sources: ['https://fr.wikipedia.org/wiki/US_Open_de_tennis', 'https://github.com/JeffSackmann/tennis_atp'] -wimbledon: - aligns: [right, left, center, center] - sources: ['https://fr.wikipedia.org/wiki/Tournoi_de_Wimbledon', 'https://github.com/JeffSackmann/tennis_atp'] diff --git a/samples/generated_by_sh.yaml b/samples/generated_by_sh.yaml new file mode 100644 index 0000000..cafd67e --- /dev/null +++ b/samples/generated_by_sh.yaml @@ -0,0 +1,62 @@ +--- +dataset: + metadatas: + generated_with: 'cfwf@0.0.1 - https://github.com/badele/cfwf' + orders: + - players + - australian_open + - roland_garros + - us_open + - wimbledon + sources: + - 'https://github.com/JeffSackmann/tennis_atp' + title: ' ATP Tour' +tables: + australian_open: + metadatas: + aligns: + - right + - left + - center + - center + sources: + - 'https://fr.wikipedia.org/wiki/Open_d%27Australie' + players: + metadatas: + aligns: + - left + - right + - left + - center + - right + - right + - right + sources: + - 'https://github.com/JeffSackmann/tennis_atp' + roland_garros: + metadatas: + aligns: + - right + - left + - center + - center + sources: + - 'https://fr.wikipedia.org/wiki/Internationaux_de_France_de_tennis' + us_open: + metadatas: + aligns: + - right + - left + - center + - center + sources: + - 'https://fr.wikipedia.org/wiki/US_Open_de_tennis' + wimbledon: + metadatas: + aligns: + - right + - left + - center + - center + sources: + - 'https://fr.wikipedia.org/wiki/Tournoi_de_Wimbledon' diff --git a/samples/generated_by_ts.cfwf b/samples/generated_by_ts.cfwf new file mode 100644 index 0000000..5658154 --- /dev/null +++ b/samples/generated_by_ts.cfwf @@ -0,0 +1,124 @@ + + ___ _____ ______ _____ + / _ \ |_ _|| ___ \ |_ _| + / /_\ \ | | | |_/ / | | ___ _ _ _ __ + | _ | | | | __/ | | / _ \ | | | || '__| + | | | | | | | | | | | (_) || |_| || | + \_| |_/ \_/ \_| \_/ \___/ \__,_||_| + + ┈┈┈ +Here is a list of the best tennis players in the ATP rankings +from 2012 to 2022, as well as the list of winners of the +4 major Grand Slam tournaments. + ┄┄┄ + +players +The best players (number of winning matches) beetween 2012-2022 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +winner_ioc name_first name_last hand height birth nbwins +────────── ────────── ───────── ──── ────── ───── ────── +SRB Novak Djokovic R 188 1987 64 +ESP Rafael Nadal L 185 1986 46 +SUI Roger Federer R 185 1981 33 +GBR Andy Murray R 190 1987 25 +GER Alexander Zverev R 198 1997 19 +AUT Dominic Thiem R 185 1993 17 +RUS Daniil Medvedev R 198 1996 16 +ESP David Ferrer R 175 1982 16 +CRO Marin Cilic R 198 1988 14 +RUS Andrey Rublev R 188 1997 13 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +The Australian Open is a tennis tournament held annually at Melbourne Park +in Melbourne, Victoria, Australia. The tournament is the first of the +four Grand Slam tennis events held each year. + +australian_open +Australian Open winners beetween 2012-2022 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +year tourney name birth nat winner +──── ─────────────── ───────── ────────────── +2022 Australian Open ESP Rafael Nadal +2021 Australian Open SRB Novak Djokovic +2020 Australian Open SRB Novak Djokovic +2019 Australian Open SRB Novak Djokovic +2018 Australian Open SUI Roger Federer +2017 Australian Open SUI Roger Federer +2016 Australian Open SRB Novak Djokovic +2015 Australian Open SRB Novak Djokovic +2014 Australian Open SUI Stan Wawrinka +2013 Australian Open SRB Novak Djokovic +2012 Australian Open SRB Novak Djokovic +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +The major tennis tournament held over two weeks at the Stade Roland Garros +in Paris, France, beginning in late May each year. The tournament and venue are +named after the French aviator Roland Garros. The French Open is the premier +clay court championship in the world and the only Grand Slam tournament +currently held on this surface. + +roland_garros +Roland Garros winners beetween 2012-2022 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +year tourney name birth nat winner +──── ───────────── ───────── ────────────── +2022 Roland Garros ESP Rafael Nadal +2021 Roland Garros SRB Novak Djokovic +2020 Roland Garros ESP Rafael Nadal +2019 Roland Garros ESP Rafael Nadal +2018 Roland Garros ESP Rafael Nadal +2017 Roland Garros ESP Rafael Nadal +2016 Roland Garros SRB Novak Djokovic +2015 Roland Garros SUI Stan Wawrinka +2014 Roland Garros ESP Rafael Nadal +2013 Roland Garros ESP Rafael Nadal +2012 Roland Garros ESP Rafael Nadal +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +The US Open Tennis Championships, commonly called the US Open, is a hardcourt tennis +tournament held annually in Queens, New York. Since 1987, the US Open has been +chronologically the fourth and final Grand Slam tournament of the year. + +us_open +US Open winners beetween 2012-2022 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +year tourney name birth nat winner +──── ──────────── ───────── ─────────────── +2022 Us Open ESP Carlos Alcaraz +2021 Us Open RUS Daniil Medvedev +2020 Us Open AUT Dominic Thiem +2019 US Open ESP Rafael Nadal +2018 US Open SRB Novak Djokovic +2017 US Open ESP Rafael Nadal +2016 US Open SUI Stan Wawrinka +2015 US Open SRB Novak Djokovic +2014 US Open CRO Marin Cilic +2013 US Open ESP Rafael Nadal +2012 US Open GBR Andy Murray +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +The Championships, commonly known simply as Wimbledon, is the oldest tennis tournament +in the world and is regarded by many as the most prestigious. +It has been held at the All England Lawn Tennis and Croquet Club in Wimbledon, London, since 1877 + +wimbledon +Wimbledon winners beetween 2012-2022 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +year tourney name birth nat winner +──── ──────────── ───────── ────────────── +2022 Wimbledon SRB Novak Djokovic +2021 Wimbledon SRB Novak Djokovic +2019 Wimbledon SRB Novak Djokovic +2018 Wimbledon SRB Novak Djokovic +2017 Wimbledon SUI Roger Federer +2016 Wimbledon GBR Andy Murray +2015 Wimbledon SRB Novak Djokovic +2014 Wimbledon SRB Novak Djokovic +2013 Wimbledon GBR Andy Murray +2012 Wimbledon SUI Roger Federer +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ diff --git a/samples/generated_by_ts.yaml b/samples/generated_by_ts.yaml new file mode 100644 index 0000000..cafd67e --- /dev/null +++ b/samples/generated_by_ts.yaml @@ -0,0 +1,62 @@ +--- +dataset: + metadatas: + generated_with: 'cfwf@0.0.1 - https://github.com/badele/cfwf' + orders: + - players + - australian_open + - roland_garros + - us_open + - wimbledon + sources: + - 'https://github.com/JeffSackmann/tennis_atp' + title: ' ATP Tour' +tables: + australian_open: + metadatas: + aligns: + - right + - left + - center + - center + sources: + - 'https://fr.wikipedia.org/wiki/Open_d%27Australie' + players: + metadatas: + aligns: + - left + - right + - left + - center + - right + - right + - right + sources: + - 'https://github.com/JeffSackmann/tennis_atp' + roland_garros: + metadatas: + aligns: + - right + - left + - center + - center + sources: + - 'https://fr.wikipedia.org/wiki/Internationaux_de_France_de_tennis' + us_open: + metadatas: + aligns: + - right + - left + - center + - center + sources: + - 'https://fr.wikipedia.org/wiki/US_Open_de_tennis' + wimbledon: + metadatas: + aligns: + - right + - left + - center + - center + sources: + - 'https://fr.wikipedia.org/wiki/Tournoi_de_Wimbledon' diff --git a/samples/initdatas/import-atp.sh b/samples/initdatas/import-atp.sh new file mode 100755 index 0000000..6a618cb --- /dev/null +++ b/samples/initdatas/import-atp.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +VERSION="3a02d8f" +DSTDIR="samples/initdatas" + +if [ ! -d "${DSTDIR}/tennis_atp" ]; then + pushd ${DSTDIR} || exit + test -d tennis_atp || git clone https://github.com/JeffSackmann/tennis_atp.git && cd tennis_atp && git checkout ${VERSION} + popd || exit + + rm -f "${DSTDIR}/samples.db" + sqlite3 -bail "${DSTDIR}/samples.db" < samples/initdatas/import-atp.sql +fi + diff --git a/samples/scripts/import-atp.sql b/samples/initdatas/import-atp.sql similarity index 51% rename from samples/scripts/import-atp.sql rename to samples/initdatas/import-atp.sql index fcdd0fa..0d4e72c 100644 --- a/samples/scripts/import-atp.sql +++ b/samples/initdatas/import-atp.sql @@ -5,25 +5,25 @@ -- BEGIN TRANSACTION; -.read './samples/scripts/init_schema.sql' - -.import --csv 'samples/tennis_atp/atp_players.csv' players - -.import --csv 'samples/tennis_atp/atp_rankings_00s.csv' rankings -.import --csv 'samples/tennis_atp/atp_rankings_10s.csv' rankings -.import --csv 'samples/tennis_atp/atp_rankings_20s.csv' rankings - -.import --csv 'samples/tennis_atp/atp_matches_2022.csv' matches -.import --csv 'samples/tennis_atp/atp_matches_2021.csv' matches -.import --csv 'samples/tennis_atp/atp_matches_2020.csv' matches -.import --csv 'samples/tennis_atp/atp_matches_2019.csv' matches -.import --csv 'samples/tennis_atp/atp_matches_2018.csv' matches -.import --csv 'samples/tennis_atp/atp_matches_2017.csv' matches -.import --csv 'samples/tennis_atp/atp_matches_2016.csv' matches -.import --csv 'samples/tennis_atp/atp_matches_2015.csv' matches -.import --csv 'samples/tennis_atp/atp_matches_2014.csv' matches -.import --csv 'samples/tennis_atp/atp_matches_2013.csv' matches -.import --csv 'samples/tennis_atp/atp_matches_2012.csv' matches +.read './samples/initdatas/init_schema.sql' + +.import --csv 'samples/initdatas/tennis_atp/atp_players.csv' players + +.import --csv 'samples/initdatas/tennis_atp/atp_rankings_00s.csv' rankings +.import --csv 'samples/initdatas/tennis_atp/atp_rankings_10s.csv' rankings +.import --csv 'samples/initdatas/tennis_atp/atp_rankings_20s.csv' rankings + +.import --csv 'samples/initdatas/tennis_atp/atp_matches_2022.csv' matches +.import --csv 'samples/initdatas/tennis_atp/atp_matches_2021.csv' matches +.import --csv 'samples/initdatas/tennis_atp/atp_matches_2020.csv' matches +.import --csv 'samples/initdatas/tennis_atp/atp_matches_2019.csv' matches +.import --csv 'samples/initdatas/tennis_atp/atp_matches_2018.csv' matches +.import --csv 'samples/initdatas/tennis_atp/atp_matches_2017.csv' matches +.import --csv 'samples/initdatas/tennis_atp/atp_matches_2016.csv' matches +.import --csv 'samples/initdatas/tennis_atp/atp_matches_2015.csv' matches +.import --csv 'samples/initdatas/tennis_atp/atp_matches_2014.csv' matches +.import --csv 'samples/initdatas/tennis_atp/atp_matches_2013.csv' matches +.import --csv 'samples/initdatas/tennis_atp/atp_matches_2012.csv' matches -- SELECT ranking_date,substr(ranking_date,1,4) as year,ioc,name_first,name_last,points -- FROM atp_rankings r INNER JOIN atp_players p ON (r.player=p.player_id) @@ -35,7 +35,7 @@ .separator "," --Top players -.output samples/players.csv +.output samples/initdatas/players.csv SELECT winner_ioc, p.name_first, p.name_last, hand, height, substr(dob,1,4) as birth,count(*) as nbwins from matches m INNER JOIN players p ON (m.winner_id=p.player_id) WHERE round="F" @@ -44,28 +44,28 @@ ORDER BY count(*) DESC LIMIT 10; -- Australian Open -.output samples/australian_open.csv +.output samples/initdatas/australian_open.csv SELECT substr(tourney_id,1,4) as year, tourney_name, winner_ioc, winner_name from matches WHERE tourney_name = "Australian Open" AND round="F" ORDER BY tourney_id desc LIMIT 11; -- Roland Garros -.output samples/roland_garros.csv +.output samples/initdatas/roland_garros.csv SELECT substr(tourney_id,1,4) as year, tourney_name, winner_ioc, winner_name from matches WHERE tourney_name = "Roland Garros" AND round="F" ORDER BY tourney_id desc LIMIT 11; -- Wimbledon -.output samples/wimbledon.csv +.output samples/initdatas/wimbledon.csv SELECT substr(tourney_id,1,4) as year, tourney_name, winner_ioc, winner_name from matches WHERE tourney_name = "Wimbledon" AND round="F" ORDER BY tourney_id desc LIMIT 11; -- Us Open -.output samples/us_open.csv +.output samples/initdatas/us_open.csv SELECT substr(tourney_id,1,4) as year, tourney_name, winner_ioc, winner_name from matches WHERE (tourney_name = "Us Open" OR tourney_name = "US Open") AND round="F" ORDER BY tourney_id desc diff --git a/samples/scripts/init_schema.sql b/samples/initdatas/init_schema.sql similarity index 100% rename from samples/scripts/init_schema.sql rename to samples/initdatas/init_schema.sql diff --git a/samples/sample.cfwf b/samples/sample.cfwf new file mode 100644 index 0000000..5658154 --- /dev/null +++ b/samples/sample.cfwf @@ -0,0 +1,124 @@ + + ___ _____ ______ _____ + / _ \ |_ _|| ___ \ |_ _| + / /_\ \ | | | |_/ / | | ___ _ _ _ __ + | _ | | | | __/ | | / _ \ | | | || '__| + | | | | | | | | | | | (_) || |_| || | + \_| |_/ \_/ \_| \_/ \___/ \__,_||_| + + ┈┈┈ +Here is a list of the best tennis players in the ATP rankings +from 2012 to 2022, as well as the list of winners of the +4 major Grand Slam tournaments. + ┄┄┄ + +players +The best players (number of winning matches) beetween 2012-2022 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +winner_ioc name_first name_last hand height birth nbwins +────────── ────────── ───────── ──── ────── ───── ────── +SRB Novak Djokovic R 188 1987 64 +ESP Rafael Nadal L 185 1986 46 +SUI Roger Federer R 185 1981 33 +GBR Andy Murray R 190 1987 25 +GER Alexander Zverev R 198 1997 19 +AUT Dominic Thiem R 185 1993 17 +RUS Daniil Medvedev R 198 1996 16 +ESP David Ferrer R 175 1982 16 +CRO Marin Cilic R 198 1988 14 +RUS Andrey Rublev R 188 1997 13 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +The Australian Open is a tennis tournament held annually at Melbourne Park +in Melbourne, Victoria, Australia. The tournament is the first of the +four Grand Slam tennis events held each year. + +australian_open +Australian Open winners beetween 2012-2022 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +year tourney name birth nat winner +──── ─────────────── ───────── ────────────── +2022 Australian Open ESP Rafael Nadal +2021 Australian Open SRB Novak Djokovic +2020 Australian Open SRB Novak Djokovic +2019 Australian Open SRB Novak Djokovic +2018 Australian Open SUI Roger Federer +2017 Australian Open SUI Roger Federer +2016 Australian Open SRB Novak Djokovic +2015 Australian Open SRB Novak Djokovic +2014 Australian Open SUI Stan Wawrinka +2013 Australian Open SRB Novak Djokovic +2012 Australian Open SRB Novak Djokovic +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +The major tennis tournament held over two weeks at the Stade Roland Garros +in Paris, France, beginning in late May each year. The tournament and venue are +named after the French aviator Roland Garros. The French Open is the premier +clay court championship in the world and the only Grand Slam tournament +currently held on this surface. + +roland_garros +Roland Garros winners beetween 2012-2022 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +year tourney name birth nat winner +──── ───────────── ───────── ────────────── +2022 Roland Garros ESP Rafael Nadal +2021 Roland Garros SRB Novak Djokovic +2020 Roland Garros ESP Rafael Nadal +2019 Roland Garros ESP Rafael Nadal +2018 Roland Garros ESP Rafael Nadal +2017 Roland Garros ESP Rafael Nadal +2016 Roland Garros SRB Novak Djokovic +2015 Roland Garros SUI Stan Wawrinka +2014 Roland Garros ESP Rafael Nadal +2013 Roland Garros ESP Rafael Nadal +2012 Roland Garros ESP Rafael Nadal +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +The US Open Tennis Championships, commonly called the US Open, is a hardcourt tennis +tournament held annually in Queens, New York. Since 1987, the US Open has been +chronologically the fourth and final Grand Slam tournament of the year. + +us_open +US Open winners beetween 2012-2022 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +year tourney name birth nat winner +──── ──────────── ───────── ─────────────── +2022 Us Open ESP Carlos Alcaraz +2021 Us Open RUS Daniil Medvedev +2020 Us Open AUT Dominic Thiem +2019 US Open ESP Rafael Nadal +2018 US Open SRB Novak Djokovic +2017 US Open ESP Rafael Nadal +2016 US Open SUI Stan Wawrinka +2015 US Open SRB Novak Djokovic +2014 US Open CRO Marin Cilic +2013 US Open ESP Rafael Nadal +2012 US Open GBR Andy Murray +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + +The Championships, commonly known simply as Wimbledon, is the oldest tennis tournament +in the world and is regarded by many as the most prestigious. +It has been held at the All England Lawn Tennis and Croquet Club in Wimbledon, London, since 1877 + +wimbledon +Wimbledon winners beetween 2012-2022 + +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +year tourney name birth nat winner +──── ──────────── ───────── ────────────── +2022 Wimbledon SRB Novak Djokovic +2021 Wimbledon SRB Novak Djokovic +2019 Wimbledon SRB Novak Djokovic +2018 Wimbledon SRB Novak Djokovic +2017 Wimbledon SUI Roger Federer +2016 Wimbledon GBR Andy Murray +2015 Wimbledon SRB Novak Djokovic +2014 Wimbledon SRB Novak Djokovic +2013 Wimbledon GBR Andy Murray +2012 Wimbledon SUI Roger Federer +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ diff --git a/samples/sample.yaml b/samples/sample.yaml new file mode 100644 index 0000000..cafd67e --- /dev/null +++ b/samples/sample.yaml @@ -0,0 +1,62 @@ +--- +dataset: + metadatas: + generated_with: 'cfwf@0.0.1 - https://github.com/badele/cfwf' + orders: + - players + - australian_open + - roland_garros + - us_open + - wimbledon + sources: + - 'https://github.com/JeffSackmann/tennis_atp' + title: ' ATP Tour' +tables: + australian_open: + metadatas: + aligns: + - right + - left + - center + - center + sources: + - 'https://fr.wikipedia.org/wiki/Open_d%27Australie' + players: + metadatas: + aligns: + - left + - right + - left + - center + - right + - right + - right + sources: + - 'https://github.com/JeffSackmann/tennis_atp' + roland_garros: + metadatas: + aligns: + - right + - left + - center + - center + sources: + - 'https://fr.wikipedia.org/wiki/Internationaux_de_France_de_tennis' + us_open: + metadatas: + aligns: + - right + - left + - center + - center + sources: + - 'https://fr.wikipedia.org/wiki/US_Open_de_tennis' + wimbledon: + metadatas: + aligns: + - right + - left + - center + - center + sources: + - 'https://fr.wikipedia.org/wiki/Tournoi_de_Wimbledon' diff --git a/samples/samplescripts/generate_samples.sh b/samples/samplescripts/generate_samples.sh new file mode 100755 index 0000000..b2fc134 --- /dev/null +++ b/samples/samplescripts/generate_samples.sh @@ -0,0 +1,94 @@ +#!/usr/bin/env bash + +CFWF="deno run -A mod.ts" + +$CFWF dataset init -c /tmp/config.json + +# Dataset definition +$CFWF dataset set \ + -c /tmp/config.json \ + -t " ATP Tour" \ + -d "$(cat << EOD +Here is a list of the best tennis players in the ATP rankings +from 2012 to 2022, as well as the list of winners of the +4 major Grand Slam tournaments. +EOD +)" \ + -m '{ "sources": [ "https://github.com/JeffSackmann/tennis_atp" ]}' + +# Players +$CFWF dataset table add \ + -c /tmp/config.json \ + -f ./samples/initdatas/players.csv \ + -t players \ + -s "The best players (number of winning matches) beetween 2012-2022" \ + -a "left,right,left,center,right,right,right" \ + -m '{ "sources": [ "https://github.com/JeffSackmann/tennis_atp" ]}' + +# Australian Open +$CFWF dataset table add \ + -c /tmp/config.json \ + -f ./samples/initdatas/australian_open.csv \ + -t "australian_open" \ + -s "Australian Open winners beetween 2012-2022" \ + -d "$(cat << EOD +The Australian Open is a tennis tournament held annually at Melbourne Park +in Melbourne, Victoria, Australia. The tournament is the first of the +four Grand Slam tennis events held each year. +EOD +)" \ + -l "year,tourney name,birth nat,winner" \ + -a "right,left,center,center" \ + -m '{ "sources": [ "https://fr.wikipedia.org/wiki/Open_d%27Australie" ]}' + +# Roland Garros +$CFWF dataset table add \ + -c /tmp/config.json \ + -f ./samples/initdatas/roland_garros.csv \ + -t "roland_garros" \ + -s "Roland Garros winners beetween 2012-2022" \ + -d "$(cat << EOD +The major tennis tournament held over two weeks at the Stade Roland Garros +in Paris, France, beginning in late May each year. The tournament and venue are +named after the French aviator Roland Garros. The French Open is the premier +clay court championship in the world and the only Grand Slam tournament +currently held on this surface. +EOD +)" \ + -l "year,tourney name,birth nat,winner" \ + -a "right,left,center,center" \ + -m '{ "sources": [ "https://fr.wikipedia.org/wiki/Internationaux_de_France_de_tennis" ]}' + +# US Open +$CFWF dataset table add \ + -c /tmp/config.json \ + -f ./samples/initdatas/us_open.csv \ + -t "us_open" \ + -s "US Open winners beetween 2012-2022" \ + -d "$(cat << EOD +The US Open Tennis Championships, commonly called the US Open, is a hardcourt tennis +tournament held annually in Queens, New York. Since 1987, the US Open has been +chronologically the fourth and final Grand Slam tournament of the year. +EOD +)" \ + -l "year,tourney name,birth nat,winner" \ + -a "right,left,center,center" \ + -m '{ "sources": [ "https://fr.wikipedia.org/wiki/US_Open_de_tennis" ]}' + +# Wimbledon +$CFWF dataset table add \ + -c /tmp/config.json \ + -f ./samples/initdatas/wimbledon.csv \ + -t "wimbledon" \ + -s "Wimbledon winners beetween 2012-2022" \ + -d "$(cat << EOD +The Championships, commonly known simply as Wimbledon, is the oldest tennis tournament +in the world and is regarded by many as the most prestigious. +It has been held at the All England Lawn Tennis and Croquet Club in Wimbledon, London, since 1877 +EOD +)" \ + -l "year,tourney name,birth nat,winner" \ + -a "right,left,center,center" \ + -m '{ "sources": [ "https://fr.wikipedia.org/wiki/Tournoi_de_Wimbledon" ]}' + +$CFWF export -c /tmp/config.json -S -f ./samples/generated_by_sh.cfwf diff --git a/samples/scripts/generate_samples.ts b/samples/samplescripts/generate_samples.ts similarity index 50% rename from samples/scripts/generate_samples.ts rename to samples/samplescripts/generate_samples.ts index de7b1bc..94fe419 100644 --- a/samples/scripts/generate_samples.ts +++ b/samples/samplescripts/generate_samples.ts @@ -1,115 +1,105 @@ +// deno run -A samples/initdatas/initdatas/generate_samples.ts + import { CFWF } from "../../src/cfwf.ts"; -import { parseCSV } from "../../src/utils.ts"; +import { readCSVFile } from "../../src/converter.ts"; -// deno-lint-ignore no-explicit-any -const metas: any = { +const samples = new CFWF({}); +samples.setDatasetProperties({ title: " ATP Tour", - comment: "Here is a list of the best tennis players in the ATP rankings\n\ + description: "Here is a list of the best tennis players in the ATP rankings\n\ from 2012 to 2022, as well as the list of winners of the\n\ 4 major Grand Slam tournaments.", - sources: [ - "https://github.com/JeffSackmann/tennis_atp", - ], -}; - -const samples = new CFWF(metas); - -const players_txt = Deno.readTextFileSync("samples/players.csv"); -const players = parseCSV(players_txt); - -const australian_txt = Deno.readTextFileSync("samples/australian_open.csv"); -const australian = parseCSV(australian_txt); - -const rgarros_txt = Deno.readTextFileSync("samples/roland_garros.csv"); -const rgarros = parseCSV(rgarros_txt); - -const usopen_txt = Deno.readTextFileSync("samples/us_open.csv"); -const usopen = parseCSV(usopen_txt); - -const wimbledon_txt = Deno.readTextFileSync("samples/wimbledon.csv"); -const wimbledon = parseCSV(wimbledon_txt); + metadatas: { + sources: [ + "https://github.com/JeffSackmann/tennis_atp", + ], + }, +}); -samples.addArray( - "players", - "The best players (number of winning matches) beetween 2012-2022 ", - "", - players.columns, - players.values, - { +const players = await readCSVFile("samples/initdatas/players.csv"); +samples.addTable("players", { + subtitle: "The best players (number of winning matches) beetween 2012-2022", + description: "", + columns: players.columns, + rows: players.rows, + metadatas: { aligns: ["left", "right", "left", "center", "right", "right", "right"], - sources: "https://github.com/JeffSackmann/tennis_atp", + sources: [ + "https://github.com/JeffSackmann/tennis_atp", + ], }, -); +}); -samples.addArray( - "australian_open", - "Australian Open winners beetween 2012-2022", +const australian_open = await readCSVFile( + "samples/initdatas/australian_open.csv", +); +samples.addTable("australian_open", { + subtitle: "Australian Open winners beetween 2012-2022", + description: "The Australian Open is a tennis tournament held annually at Melbourne Park\n\ -in Melbourne, Victoria, Australia. The tournament is the first of the \n\ +in Melbourne, Victoria, Australia. The tournament is the first of the\n\ four Grand Slam tennis events held each year.", - ["year", "tourney name", "birth nat", "winner"], - australian.values, - { + columns: ["year", "tourney name", "birth nat", "winner"], + rows: australian_open.rows, + metadatas: { aligns: ["right", "left", "center", "center"], sources: [ "https://fr.wikipedia.org/wiki/Open_d%27Australie", - "https://github.com/JeffSackmann/tennis_atp", ], }, -); +}); -samples.addArray( - "roland_garros", - "Roland Garros winners beetween 2012-2022", -"The major tennis tournament held over two weeks at the Stade Roland Garros \n\ +const rgarros = await readCSVFile("samples/initdatas/roland_garros.csv"); +samples.addTable("roland_garros", { + subtitle: "Roland Garros winners beetween 2012-2022", + description: +"The major tennis tournament held over two weeks at the Stade Roland Garros\n\ in Paris, France, beginning in late May each year. The tournament and venue are\n\ named after the French aviator Roland Garros. The French Open is the premier\n\ clay court championship in the world and the only Grand Slam tournament\n\ currently held on this surface.", - ["year", "tourney name", "birth nat", "winner"], - rgarros.values, - { + columns: ["year", "tourney name", "birth nat", "winner"], + rows: rgarros.rows, + metadatas: { aligns: ["right", "left", "center", "center"], sources: [ "https://fr.wikipedia.org/wiki/Internationaux_de_France_de_tennis", - "https://github.com/JeffSackmann/tennis_atp", ], }, -); +}); -samples.addArray( - "us_open", - "US Open winners beetween 2012-2022", +const usopen = await readCSVFile("samples/initdatas/us_open.csv"); +samples.addTable("us_open", { + subtitle: "US Open winners beetween 2012-2022", + description: "The US Open Tennis Championships, commonly called the US Open, is a hardcourt tennis\n\ -tournament held annually in Queens, New York. Since 1987, the US Open has been \n\ +tournament held annually in Queens, New York. Since 1987, the US Open has been\n\ chronologically the fourth and final Grand Slam tournament of the year.", - ["year", "tourney name", "birth nat", "winner"], - usopen.values, - { + columns: ["year", "tourney name", "birth nat", "winner"], + rows: usopen.rows, + metadatas: { aligns: ["right", "left", "center", "center"], sources: [ "https://fr.wikipedia.org/wiki/US_Open_de_tennis", - "https://github.com/JeffSackmann/tennis_atp", ], }, -); +}); -samples.addArray( - "wimbledon", - "wimbledon winners beetween 2012-2022", +const wimbledon = await readCSVFile("samples/initdatas/wimbledon.csv"); +samples.addTable("wimbledon", { + subtitle: "Wimbledon winners beetween 2012-2022", + description: "The Championships, commonly known simply as Wimbledon, is the oldest tennis tournament\n\ in the world and is regarded by many as the most prestigious.\n\ It has been held at the All England Lawn Tennis and Croquet Club in Wimbledon, London, since 1877", - ["year", "tourney name", "birth nat", "winner"], - wimbledon.values, - { + columns: ["year", "tourney name", "birth nat", "winner"], + rows: wimbledon.rows, + metadatas: { aligns: ["right", "left", "center", "center"], sources: [ "https://fr.wikipedia.org/wiki/Tournoi_de_Wimbledon", - "https://github.com/JeffSackmann/tennis_atp", ], }, -); +}); -const content = await samples.toCFWF({}); -Deno.writeTextFileSync("samples.cfwf", content); +samples.saveCFWF("./samples/generated_by_ts.cfwf", true); diff --git a/samples/samplescripts/sample-config.yaml b/samples/samplescripts/sample-config.yaml new file mode 100644 index 0000000..870e608 --- /dev/null +++ b/samples/samplescripts/sample-config.yaml @@ -0,0 +1,127 @@ +--- +_dataset_: + title: " ATP Tour" + comment: > + Here is a list of the best tennis players in the ATP rankings + from 2012 to 2022, as well as the list of winners of the + 4 major Grand Slam tournaments. + metadatas: + sources: + - https://github.com/JeffSackmann/tennis_atp + font: doom + removetitlelines: 2 +tables: + players: + tablename: players + subtitle: The best players (number of winning matches) beetween 2012-2022 + comment: "" + columns: + - winner_ioc + - name_first + - name_last + - hand + - height + - birth + - nbwins + metadatas: + aligns: + - left + - right + - left + - center + - right + - right + - right + sources: https://github.com/JeffSackmann/tennis_atp + australian_open: + tablename: australian_open + subtitle: Australian Open winners beetween 2012-2022 + comment: > + The Australian Open is a tennis tournament held annually at Melbourne Park + in Melbourne, Victoria, Australia. The tournament is the first of the + four Grand Slam tennis events held each year. + columns: + - year + - tourney name + - birth nat + - winner + metadatas: + aligns: + - right + - left + - center + - center + sources: + - https://fr.wikipedia.org/wiki/Open_d%27Australie + - https://github.com/JeffSackmann/tennis_atp + roland_garros: + tablename: roland_garros + subtitle: Roland Garros winners beetween 2012-2022 + comment: > + The major tennis tournament held over two weeks at the Stade Roland Garros + in Paris, France, beginning in late May each year. + The tournament and venue are named after the French aviator + Roland Garros The French Open is the premier clay court championship + in the world and the only Grand Slam tournament currently held + on this surface. + columns: + - year + - tourney name + - birth nat + - winner + metadatas: + aligns: + - right + - left + - center + - center + sources: + - https://fr.wikipedia.org/wiki/Internationaux_de_France_de_tennis + - https://github.com/JeffSackmann/tennis_atp + us_open: + tablename: us_open + subtitle: US Open winners beetween 2012-2022 + comment: > + The US Open Tennis Championships, commonly called the US Open, + is a hardcourt tennis tournament held annually in Queens, + New York. Since 1987, the US Open has been + + chronologically the fourth and final Grand Slam tournament of the year. + columns: + - year + - tourney name + - birth nat + - winner + metadatas: + aligns: + - right + - left + - center + - center + sources: + - https://fr.wikipedia.org/wiki/US_Open_de_tennis + - https://github.com/JeffSackmann/tennis_atp + wimbledon: + tablename: wimbledon + subtitle: wimbledon winners beetween 2012-2022 + comment: > + The Championships, commonly known simply as Wimbledon, + is the oldest tennis tournament in the world and is regarded + by many as the most prestigious. It has been held at the + All England Lawn Tennis and Croquet Club in Wimbledon, London, since 1877 + columns: + - year + - tourney name + - birth nat + - winner + metadatas: + aligns: + - right + - left + - center + - center + sources: + - https://fr.wikipedia.org/wiki/Tournoi_de_Wimbledon + - https://github.com/JeffSackmann/tennis_atp +generatedtitle: [] +maxwidthtitle: 0 diff --git a/samples/scripts/import-atp.sh b/samples/scripts/import-atp.sh deleted file mode 100755 index 6f1a997..0000000 --- a/samples/scripts/import-atp.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -cd samples || exit -test -d tennis_atp || git clone https://github.com/JeffSackmann/tennis_atp.git && cd tennis_atp && git checkout 3a02d8f - -cd ../.. -rm -f samples/samples.db -sqlite3 -bail samples/samples.db < samples/scripts/import-atp.sql diff --git a/src/cfwf.ts b/src/cfwf.ts index 159aef3..e02f647 100644 --- a/src/cfwf.ts +++ b/src/cfwf.ts @@ -1,45 +1,62 @@ -import { Align, readerOptions, writerOptions } from "./types.ts"; +import { + Align, + CFWFDataset, + CFWFOptions, + DatasetType, + ExportTable, + FormatCFWF, + TableType, +} from "./types.ts"; import { AvailableFonts } from "https://deno.land/x/deno_figlet@1.0.0/src/types.ts"; -import { Table } from "./table.ts"; +import { existsSync } from "https://deno.land/std@0.205.0/fs/exists.ts"; import { align, getMaxWidth, max, searchMarker } from "./utils.ts"; import { modfmt, modyaml, text } from "../deps.ts"; import { version } from "./version.ts"; -const footertitle = "Generated with https://github.com/badele/cfwf"; +const footertitle = "cfwf@{VERSION} - https://github.com/badele/cfwf"; export class CFWF { - // deno-lint-ignore no-explicit-any - infos: any; - tables: Record; + config: CFWFDataset; + writeroptions: CFWFOptions; // Title generatedtitle: string[]; maxwidthtitle: number; - // deno-lint-ignore no-explicit-any - constructor(infos: any) { - if (!infos.font && infos.title) infos.font = "doom"; - // if (infos.generatedtitle) delete infos.title; - // if (!infos.title && !infos.generatedtitle) infos.title = "VIDE"; - if (!infos.comment) infos.comment = ""; - if (!infos.removetitlelines) infos.removetitlelines = 2; + constructor(dsconfig: CFWFDataset) { + dsconfig.dataset = dsconfig.dataset || {}; + dsconfig.tables = dsconfig.tables || {}; - this.infos = infos; - this.tables = {}; - - // Title + this.config = dsconfig; this.generatedtitle = []; this.maxwidthtitle = 0; + + this.writeroptions = { + padding: 3, + chartitlesep: "┈", + chardescsep: "┄", + chartabletop: "━", + chartablemiddle: "─", + chartablebottom: "━", + charyamlsep: "╌", + }; } async _generateTitle(): Promise { - const txttitle = await text( - this.infos.title, - this.infos.font as AvailableFonts, - ); + let { dataset } = this.config; + const defaultDataset = { title: "", description: "" }; + dataset = dataset || defaultDataset; + + let { title, metadatas } = dataset; + metadatas = metadatas || {}; + + const font = metadatas.font as AvailableFonts ?? "doom"; + const removetitlelines = metadatas.removetitlelines ?? 2; + + const txttitle = await text(title ?? "", font); const ageneratedtitle = txttitle.split("\n").slice( 0, - -this.infos.removetitlelines, + -removetitlelines, ); const maxwidthtitle = getMaxWidth(ageneratedtitle); @@ -47,65 +64,104 @@ export class CFWF { this.maxwidthtitle = maxwidthtitle; } - addArray( - tablename: string, - subtitle: string, - comment: string, - columns: string[], - // deno-lint-ignore no-explicit-any - rows: any[], - // deno-lint-ignore no-explicit-any - infos: any, - ): void { - this.tables[tablename] = new Table( - tablename, - subtitle, - comment, - columns, - rows, - infos, - ); + setDatasetProperties(params: DatasetType): void { + const dataset = this.config.dataset || {}; + + if (params) Object.assign(dataset, params); + } + + addTable(tablename: string, params: TableType): void { + const tables = this.config.tables || {}; + const table = tables[tablename] || {}; + + const dataset = this.config.dataset || {}; + dataset.metadatas = dataset.metadatas || {}; + dataset.metadatas.orders = dataset.metadatas.orders || []; + dataset.metadatas.orders.push(tablename); + + if (params) Object.assign(table, params); + + tables[tablename] = table; + } + + getDatas(): Record { + const tables = this.config?.tables || {}; + + const orders = this.config?.dataset?.metadatas?.orders || []; + const result: Record = {}; + + for (const tablename of orders) { + const table = tables[tablename] as TableType; + if (table) { + result[tablename] = { + columns: table.columns || [], + rows: table.rows || [], + }; + } + } + + return result; + } + + async saveCFWF( + filename: string, + separate: boolean, + ): Promise { + const { content, metadatas } = await this.outputCFWF(separate); + + const metaname = filename.replace(".cfwf", ".yaml"); + if (!separate) { + await Deno.writeTextFile( + filename, + content, + ); + if (existsSync(metaname) === true) { + await Deno.remove(metaname); + } + } else { + Deno.writeTextFileSync(filename, content); + const metaname = filename.replace(".cfwf", ".yaml"); + Deno.writeTextFileSync(metaname, metadatas); + } } - fromCFWF(content: string, { - charseparator = "┈", - chartabletop = "━", - chartablemiddle = "─", - chartablebottom = "━", - }: readerOptions): void { + importCFWF(content: string): void { + const chartitlesep = this.writeroptions.chartitlesep ?? "┈"; + const chardescsep = this.writeroptions.chardescsep ?? "┄"; + const chartabletop = this.writeroptions.chartabletop ?? "━"; + const chartablemiddle = this.writeroptions.chartablemiddle ?? "─"; + const chartablebottom = this.writeroptions.chartablebottom ?? "━"; + const charyamlsep = this.writeroptions.charyamlsep ?? "╌"; + let lastmarkerpos = 0; let tabletopmarkerpos = 0; let tablebottommarkerpos = 0; let tabletablenamepos = 0; let tablesubtitlepos = 0; - // deno-lint-ignore no-explicit-any - let fromYAML: any = {}; - const tables: Table[] = []; - const lines = content.split("\n"); - // Search title and comment - const titlemarkerpos = searchMarker(lines, charseparator); - const commentmarkerpos = searchMarker( - lines, - charseparator, - titlemarkerpos + 1, - ); - lastmarkerpos = commentmarkerpos + 1; - - let endfile = false; - while (!endfile) { - const table: Table = { - tablename: "", - subtitle: "", - comment: "", - columns: [], - // aligns: [], - rows: [], - metas: {}, - }; + // Search title and description separators + const titlemarkerpos = searchMarker(lines, chartitlesep); + const descmarkerpos = searchMarker(lines, chardescsep); + const yamlmarkerpos = searchMarker(lines, charyamlsep); + lastmarkerpos = max(titlemarkerpos, descmarkerpos); + + this.config = modyaml.parse( + lines.slice(yamlmarkerpos + 1, -1).join("\n"), + ) as CFWFDataset; + const dataset = this.config.dataset || {}; + + if (descmarkerpos > -1) { + dataset.description = lines.slice( + titlemarkerpos + 1, + descmarkerpos, + ).join("\n"); + } + + let hastable = searchMarker(lines, chartabletop, lastmarkerpos); + while (hastable > -1) { tabletopmarkerpos = searchMarker(lines, chartabletop, lastmarkerpos); if (tabletopmarkerpos > -1) { // search table @@ -117,10 +173,16 @@ export class CFWF { tabletablenamepos = tabletopmarkerpos - 3; tablesubtitlepos = tabletopmarkerpos - 2; + const tablename = lines[tabletablenamepos]; + + this.config.tables = this.config.tables || {}; + const table = this.config.tables[tablename]; - table.tablename = lines[tabletablenamepos]; table.subtitle = lines[tablesubtitlepos]; - table.comment = lines.slice(lastmarkerpos + 1, tabletablenamepos - 1) + table.description = lines.slice( + lastmarkerpos + 1, + tabletablenamepos - 1, + ) .join("\n"); const headerline = lines[tabletopmarkerpos + 1]; @@ -166,98 +228,110 @@ export class CFWF { rows.push(cols); } table.rows = rows; - tables.push(table); lastmarkerpos = tablebottommarkerpos + 1; - } else { - endfile = true; - fromYAML = modyaml.parse(lines.slice(lastmarkerpos, -1).join("\n")); - this.infos = fromYAML._infos_; - - this.generatedtitle = lines.slice(0, titlemarkerpos); - this.infos.comment = lines.slice( - titlemarkerpos + 1, - commentmarkerpos, - ).join("\n"); + + hastable = searchMarker(lines, chartabletop, lastmarkerpos); } } - this._generateTitle(); - for (let idx = 0; idx < tables.length; idx++) { - const table = tables[idx]; - - this.addArray( - table.tablename, - table.subtitle, - table.comment, - table.columns, - // global[table.tablename].aligns, - table.rows, - table.metas = fromYAML[table.tablename], - ); - } + // console.log("GETDATAS", this.getDatas()); } - async toCFWF({ - padding = 3, - charseparator = "┈", - chartabletop = "━", - chartablemiddle = "─", - chartablebottom = "━", - }: writerOptions = {}): Promise { - // deno-lint-ignore no-explicit-any - const infos: any = {}; + async outputCFWF(separate: boolean): Promise { + const padding = this.writeroptions.padding ?? 3; + const chartitlesep = this.writeroptions.chartitlesep ?? "┈"; + const chardescsep = this.writeroptions.chardescsep ?? "┄"; + const chartabletop = this.writeroptions.chartabletop ?? "━"; + const chartablemiddle = this.writeroptions.chartablemiddle ?? "─"; + const chartablebottom = this.writeroptions.chartablebottom ?? "━"; + const charyamlsep = this.writeroptions.charyamlsep ?? "╌"; const lines: string[] = []; - let maxwidthcomment = 0; + let maxwidthdescription = 0; + + const config = structuredClone(this.config); + + let { dataset, tables } = config as CFWFDataset; + const defaultDataset = { + title: "", + description: "", + generatedtitle: "", + metadatas: { + orders: [], + }, + }; + + dataset = dataset || defaultDataset; + tables = tables || {}; + const metadatas = dataset.metadatas || {}; + + let { title, generatedtitle, description } = dataset; - // Compute max title width size - if (this.infos.title) { + // Compute max dataset title width size + if (title && title.length > 0) { await this._generateTitle(); - } else { - if (this.infos.generatedtitle) { - this.generatedtitle = this.infos.generatedtitle.split("\n"); - this.maxwidthtitle = getMaxWidth(this.generatedtitle); - } + } + if (generatedtitle) { + this.generatedtitle = generatedtitle.split("\n"); + this.maxwidthtitle = getMaxWidth(this.generatedtitle); } - // Compute max comment width size - if (this.infos.comment) { - const acomment = this.infos.comment.split("\n"); - maxwidthcomment = getMaxWidth(acomment); + // Compute max dataset description width size + if (description && description.length > 0) { + description = description.replaceAll("\\n", "\n"); + const adescription = description.split("\n"); + maxwidthdescription = getMaxWidth(adescription); } + // Compute title or description max size + const maxwidthline = max(this.maxwidthtitle, maxwidthdescription); - // Compute title or comment max size - const maxwidthline = max(this.maxwidthtitle, maxwidthcomment); if (this.generatedtitle && this.generatedtitle.length > 0) { lines.push(this.generatedtitle.join("\n")); - lines.push(align("center", charseparator.repeat(3), maxwidthline)); + lines.push( + align( + "center", + chartitlesep.repeat(3), + maxwidthline, + ), + ); } - if (this.infos.comment && this.infos.comment.length > 0) { - lines.push(this.infos.comment); - lines.push(align("center", charseparator.repeat(3), maxwidthline)); + if (description && description.length > 0) { + lines.push(description); + lines.push(align("center", chardescsep.repeat(3), maxwidthline)); } // Generate tables - let table: Table; - const tablenames = Object.keys(this.tables); - tablenames.forEach((tablename) => { - table = this.tables[tablename]; + const tablenames = metadatas.orders || []; + for (const tablename of tablenames) { + const table = tables[tablename]; + + const defaultTable = { + title: "", + description: "", + rows: [], + columns: [], + metadatas: {}, + }; + + let { metadatas: tmetadatas } = table || defaultTable; + tmetadatas = tmetadatas || {}; //search the needed number of float size for each columns const colnbfloat: Record = {}; - for (let ridx = 0; ridx < table.rows.length; ridx++) { - const row = table.rows[ridx]; - for (let cidx = 0; cidx < row.length; cidx++) { - const col = row[cidx]; - if (typeof col === "number") { - const colvalue = col.toString(); - const dotpos = colvalue.indexOf("."); - colnbfloat[cidx] = max( - colnbfloat[cidx], - (dotpos != -1) ? colvalue.length - dotpos - 1 : 0, - ); + if (table.rows) { + for (const row of table.rows) { + for (let cidx = 0; cidx < row.length; cidx++) { + const col = row[cidx]; + if (typeof col === "number") { + const colvalue = col.toString(); + const dotpos = colvalue.indexOf("."); + colnbfloat[cidx] = max( + colnbfloat[cidx], + (dotpos != -1) ? colvalue.length - dotpos - 1 : 0, + ); + } } } } @@ -265,53 +339,61 @@ export class CFWF { // Compute number floats needed for each columns // deno-lint-ignore no-explicit-any const srows: any[] = []; - for (let ridx = 0; ridx < table.rows.length; ridx++) { - const row = table.rows[ridx]; - // deno-lint-ignore no-explicit-any - const cols: any[] = []; - for (let cidx = 0; cidx < row.length; cidx++) { - // const colname = table.columns[cidx]; - const col = row[cidx]; - if (typeof col === "number" && colnbfloat[cidx] > 0) { - cols.push(modfmt.sprintf("%.*f", colnbfloat[cidx], col)); - } else { - cols.push(col.toString()); + + if (table.rows) { + for (const row of table.rows) { + // deno-lint-ignore no-explicit-any + const cols: any[] = []; + for (let cidx = 0; cidx < row.length; cidx++) { + const col = row[cidx]; + + if (typeof col === "number" && colnbfloat[cidx] > 0) { + cols.push(modfmt.sprintf("%.*f", colnbfloat[cidx], col)); + } else { + cols.push(col.toString()); + } } + srows.push(cols); } - srows.push(cols); } // Init columns size with the header size - const columnssize: number[] = []; - for (let idx = 0; idx < table.columns.length; idx++) { - columnssize.push(table.columns[idx].length); - } + let { columns } = table; + columns = columns || []; + + const columnssize: number[] = columns.map((col) => col.length); // compute the content columns size - for (let rowidx = 0; rowidx < srows.length; rowidx++) { - const itemrow = srows[rowidx]; + for (const itemrow of srows) { for (let colidx = 0; colidx < itemrow.length; colidx++) { const content = itemrow[colidx]; columnssize[colidx] = max(content.length, columnssize[colidx]); } } - // compute total line size - let headerlinesize = 0; - for (let idx = 0; idx < table.columns.length; idx++) { - if (idx > 0) headerlinesize += padding; - headerlinesize += columnssize[idx]; + let { aligns } = tmetadatas || []; + + if (!aligns) { + aligns = Array(columns.length).fill("left"); } + tmetadatas.aligns = aligns; + + // compute total line size + const headerlinesize = columnssize.reduce((acc, size) => acc + size, 0) + + (padding * (columns.length - 1)); // add tablename and subtitle - if (table.comment) { + if (table.description) { lines.push(""); - lines.push(table.comment); + lines.push(table.description); + } + + lines.push(""); + if (tablename) { + lines.push(tablename); } if (table.subtitle) { - lines.push(""); - lines.push(table.tablename); lines.push(table.subtitle); lines.push(""); } @@ -323,8 +405,8 @@ export class CFWF { const headers: string[] = []; const middlelineheader: string[] = []; - for (let idx = 0; idx < table.columns.length; idx++) { - const cname = table.columns[idx]; + for (let idx = 0; idx < columns.length; idx++) { + const cname = columns[idx]; const csize = columnssize[idx]; if (idx > 0) { @@ -332,7 +414,11 @@ export class CFWF { middlelineheader.push(" ".repeat(padding)); } - headers.push(align(table.metas.aligns[idx] as Align, cname, csize)); + if (aligns) { + headers.push( + align(aligns[idx] as Align, cname, csize), + ); + } middlelineheader.push(chartablemiddle.repeat(csize)); } @@ -350,35 +436,47 @@ export class CFWF { if (colidx > 0) line.push(" ".repeat(padding)); // line.push(coldata[colidx].padEnd(csize)); - line.push( - align(table.metas.aligns[colidx] as Align, coldata[colidx], csize), - ); + + if (aligns) { + line.push( + align( + aligns[colidx] as Align, + coldata[colidx], + csize, + ), + ); + } } lines.push(line.join("")); - - infos[tablename] = {}; - infos[tablename]["aligns"] = table.metas.aligns; - - // Add another metas to export - Object.keys(table.metas).forEach((key) => - infos[tablename][key] = table.metas[key] - ); } // Add bottom line header if (chartablebottom) lines.push(chartablebottom.repeat(headerlinesize)); - }); - - // Add another metas to export - infos._infos_ = structuredClone(this.infos); - infos._infos_.removetitlelines = this.infos.removetitlelines; - infos._infos_.generated_with = `${footertitle}@${version}`; - delete infos._infos_.comment; + } lines.push(""); - const smeta = modyaml.stringify(infos, { flowLevel: 2, sortKeys: true }); - lines.push(smeta); - return lines.join("\n"); + delete dataset.description; + + metadatas.generated_with = footertitle.replaceAll("{VERSION}", version); + + for (const table of Object.values(tables)) { + delete table.columns; + delete table.description; + delete table.rows; + delete table.subtitle; + } + + dataset.metadatas = metadatas; + + const smeta = modyaml.stringify(config, { sortKeys: true }); + + if (!separate) { + lines.push(charyamlsep.repeat(3)); + lines.push(smeta); + return { content: lines.join("\n"), metadatas: "" }; + } else { + return { content: lines.join("\n"), metadatas: `---\n${smeta}` }; + } } } diff --git a/src/cfwf_test.ts b/src/cfwf_test.ts index e72fea0..78f833c 100644 --- a/src/cfwf_test.ts +++ b/src/cfwf_test.ts @@ -1,16 +1,30 @@ // mod_test.ts import { CFWF } from "./cfwf.ts"; -import { assertEquals, assertGreater, assertThrows } from "../test_deps.ts"; +import { assertEquals } from "../test_deps.ts"; import { modyaml } from "../deps.ts"; -import { searchMarker } from "./utils.ts"; +import { CHARMARKERS, searchMarker } from "./utils.ts"; import { version } from "./version.ts"; -import { writerOptions } from "./types.ts"; +import { CFWFOptions } from "./types.ts"; +import { readTextCFWFFile } from "./converter.ts"; const { test } = Deno; const title = "this is a title"; const comment = "this is a comment"; -const footer = "Generated with https://github.com/badele/cfwf"; +const footer = `cfwf@${version} - https://github.com/badele/cfwf`; + +// const sep: readerOptions = { +// chartitlesep: "┈", +// chardescsep: "┄", +// chartabletop: "━", +// chartablemiddle: "─", +// chartablebottom: "━", +// charyamlsep: "╌", +// }; + +const chartitlesep = CHARMARKERS.chartitlesep || ""; +const chardescsep = CHARMARKERS.chardescsep || ""; +const charyamlsep = CHARMARKERS.charyamlsep || ""; const datas_array = [ [1, 1, 1, 1, 1], @@ -35,161 +49,198 @@ const datas_array_options = { "center", "DEFAULTLEFT", ], - title: "Test", }; -const datas_dict = [ - { "Id": 1, "larger column": 1, "right": 1, "center": 1, "left": 1 }, - { "Id": 2, "larger column": 22, "right": 22, "center": 222, "left": 22 }, - { - "Id": 3, - "larger column": 12.43, - "right": 333, - "center": 33333, - "left": 333, - }, - { - "Id": 4, - "larger column": .123, - "right": 4444, - "center": 4444444, - "left": 4444, - }, - { - "Id": 5, - "larger column": "", - "right": 55555, - "center": 555555555, - "left": 55555, - }, -]; - -const datas_dict_options = { - columns: [], - aligns: [ - "right", - "right", - "right", - "center", - "DEFAULTLEFT", - ], - title: "Test", -}; +// const datas_dict = [ +// { "Id": 1, "larger column": 1, "right": 1, "center": 1, "left": 1 }, +// { "Id": 2, "larger column": 22, "right": 22, "center": 222, "left": 22 }, +// { +// "Id": 3, +// "larger column": 12.43, +// "right": 333, +// "center": 33333, +// "left": 333, +// }, +// { +// "Id": 4, +// "larger column": .123, +// "right": 4444, +// "center": 4444444, +// "left": 4444, +// }, +// { +// "Id": 5, +// "larger column": "", +// "right": 55555, +// "center": 555555555, +// "left": 55555, +// }, +// ]; + +// const datas_dict_options = { +// columns: [], +// metadatas: { +// aligns: [ +// "right", +// "right", +// "right", +// "center", +// "DEFAULTLEFT", +// ], +// }, +// }; test("Generated title", async () => { + const title = "this is a title\nis\ngenerated by other tools"; const samples = new CFWF({ - generatedtitle: "this is a title\nis\ngenerated by other tools", - comment: "", + dataset: { + generatedtitle: title, + description: "", + }, }); - const content = await samples.toCFWF({}); - const lines = content.split("\n"); + + const formater = await samples.outputCFWF(false); + const lines = formater.content.split("\n"); + + const titlemarkerpos = searchMarker(lines, chartitlesep || ""); + const descmarkerpos = searchMarker(lines, chardescsep || ""); + const yamlmarkerpos = searchMarker(lines, charyamlsep || ""); + + assertEquals(3, titlemarkerpos); + assertEquals(-1, descmarkerpos); + assertEquals(5, yamlmarkerpos); assertEquals("generated by other tools", lines[2]); - assertEquals(10, lines.length); + assertEquals(15, lines.length); // deno-lint-ignore no-explicit-any - const dsinfos: any = modyaml.parse(lines.slice(4).join("\n")); - const keys = Object.keys(dsinfos._infos_); - assertEquals(keys, [ - "generated_with", + const dsinfos: any = modyaml.parse( + lines.slice(yamlmarkerpos + 1).join("\n"), + ); + + const keys = Object.keys(dsinfos.dataset); + + assertEquals([ "generatedtitle", - "removetitlelines", - ]); + "metadatas", + ], keys); }); test("Empty data", async () => { const samples = new CFWF({}); - const content = await samples.toCFWF({}); - const lines = content.split("\n"); + const formated = await samples.outputCFWF(false); + const lines = formated.content.split("\n"); + + const titlemarkerpos = searchMarker(lines, chartitlesep || ""); + const descmarkerpos = searchMarker(lines, chardescsep || ""); + const yamlmarkerpos = searchMarker(lines, charyamlsep || ""); + + assertEquals(-1, titlemarkerpos); + assertEquals(-1, descmarkerpos); + assertEquals(1, yamlmarkerpos); - assertEquals("", lines[0]); - assertEquals(5, lines.length); + assertEquals(7, lines.length); // deno-lint-ignore no-explicit-any - const dsinfos: any = modyaml.parse(lines.join("\n")); - const keys = Object.keys(dsinfos._infos_); + const dsinfos: any = modyaml.parse(lines.slice(yamlmarkerpos + 1).join("\n")); + const datasetkeys = Object.keys(dsinfos.dataset); assertEquals([ - "generated_with", - "removetitlelines", - ], keys); - assertEquals(`${footer}@${version}`, dsinfos._infos_.generated_with); + "metadatas", + ], datasetkeys); + assertEquals( + `${footer}`, + dsinfos.dataset.metadatas.generated_with, + ); }); test("Title", async () => { // test title const samples = new CFWF({ - title: title, + dataset: { + title: title, + }, }); - const content = await samples.toCFWF({}); - const lines = content.split("\n"); + const formated = await samples.outputCFWF(false); + const lines = formated.content.split("\n"); - assertEquals(16, lines.length); - assertGreater(lines[8].indexOf("┈"), 0); + const titlemarkerpos = searchMarker(lines, chartitlesep || ""); + const descmarkerpos = searchMarker(lines, chardescsep || ""); + const yamlmarkerpos = searchMarker(lines, charyamlsep || ""); + + assertEquals(8, titlemarkerpos); + assertEquals(-1, descmarkerpos); + assertEquals(10, yamlmarkerpos); + + assertEquals(17, lines.length); // deno-lint-ignore no-explicit-any - const dsinfos: any = modyaml.parse(lines.slice(9).join("\n")); - const keys = Object.keys(dsinfos._infos_); - assertEquals(keys, [ - "font", - "generated_with", - "removetitlelines", + const dsinfos: any = modyaml.parse( + lines.slice(yamlmarkerpos + 1).join("\n"), + ); + const keys = Object.keys(dsinfos.dataset); + + assertEquals([ + "metadatas", "title", - ]); - assertEquals(title, dsinfos._infos_.title); - assertEquals("doom", dsinfos._infos_.font); - assertEquals(`${footer}@${version}`, dsinfos._infos_.generated_with); + ], keys); + + assertEquals(title, dsinfos.dataset.title); + assertEquals( + `${footer}`, + dsinfos.dataset.metadatas.generated_with, + ); }); test("Title & comment", async () => { // test title and comment const samples = new CFWF({ - title: title, - comment: comment, + dataset: { + title: title, + description: comment, + }, }); - const content = await samples.toCFWF({}); - const lines = content.split("\n"); + const formated = await samples.outputCFWF(false); + const lines = formated.content.split("\n"); - assertEquals(18, lines.length); - assertGreater(lines[8].indexOf("┈"), 0); - assertGreater(lines[10].indexOf("┈"), 0); + const titlemarkerpos = searchMarker(lines, chartitlesep || ""); + const descmarkerpos = searchMarker(lines, chardescsep || ""); + const yamlmarkerpos = searchMarker(lines, charyamlsep || ""); + + assertEquals(8, titlemarkerpos); + assertEquals(10, descmarkerpos); + assertEquals(12, yamlmarkerpos); // deno-lint-ignore no-explicit-any - const dsinfos: any = modyaml.parse(lines.slice(11).join("\n")); - const keys = Object.keys(dsinfos._infos_); - assertEquals(keys, [ - "font", - "generated_with", - "removetitlelines", + const dsinfos: any = modyaml.parse(lines.slice(yamlmarkerpos + 1).join("\n")); + const keys = Object.keys(dsinfos.dataset); + assertEquals([ + "metadatas", "title", - ]); - assertEquals(title, dsinfos._infos_.title); - assertEquals("doom", dsinfos._infos_.font); - assertEquals(`${footer}@${version}`, dsinfos._infos_.generated_with); + ], keys); + assertEquals(title, dsinfos.dataset.title); + assertEquals(`${footer}`, dsinfos.dataset.metadatas.generated_with); }); -test("Columns and headers columns size from samples.cfwf", () => { - const options: writerOptions = { - charseparator: "┈", +test("Columns and headers columns size from sample.cfwf", async () => { + const options: CFWFOptions = { chartabletop: "━", chartablemiddle: "─", chartablebottom: "━", }; - const content = Deno.readTextFileSync("samples.cfwf"); + const content = await readTextCFWFFile("samples/sample.cfwf"); const lines = content.split("\n"); - // Search title and comment marker - const titlemarkerpos = searchMarker(lines, options.charseparator || ""); - const commentmarkerpos = searchMarker( - lines, - options.charseparator || "", - titlemarkerpos + 1, - ); + const titlemarkerpos = searchMarker(lines, chartitlesep || ""); + const descmarkerpos = searchMarker(lines, chardescsep || ""); + const yamlmarkerpos = searchMarker(lines, charyamlsep || ""); + assertEquals(8, titlemarkerpos); - assertEquals(12, commentmarkerpos); + assertEquals(12, descmarkerpos); + assertEquals(125, yamlmarkerpos); let beginheadermarker = searchMarker(lines, options.chartabletop || ""); let endheadermarker = searchMarker( @@ -243,154 +294,125 @@ test("Columns and headers columns size from samples.cfwf", () => { ); }); -test("No row", () => { - const samples = new CFWF({ - title: title, - comment: comment, - }); - - assertThrows( - () => { - samples.addArray( - "number", - "test numbers", - "", - datas_array_options.columns, - [], - datas_array_options, - ); - }, - Error, - "Table has no data", - ); -}); - -test("Number col and columns", () => { - const samples = new CFWF({ - title: title, - comment: comment, - }); - - assertThrows( - () => { - samples.addArray( - "number", - "test numbers", - "", - ["one columns"], - datas_array, - datas_array_options, - ); - }, - Error, - "They have 5 columns and 1 renamed columns", - ); -}); - -test("Aligns provided", () => { - const samples = new CFWF({ - title: title, - comment: comment, - }); - - const newoptions = structuredClone(datas_array_options); - newoptions.aligns = ["onealign"]; - assertThrows( - () => { - samples.addArray( - "number", - "test numbers", - "", - datas_array_options.columns, - datas_array, - newoptions, - ); - }, - Error, - "They have 5 columns and 1 aligns", - ); - - delete newoptions.aligns; - assertThrows( - () => { - samples.addArray( - "number", - "test numbers", - "", - datas_array_options.columns, - datas_array, - newoptions, - ); - }, - Error, - "No aligns metadatas found", - ); -}); +// test("No row", () => { +// const samples = new CFWF({ +// title: title, +// comment: comment, +// }); +// +// assertThrows( +// () => { +// samples.addArray( +// "number", +// "test numbers", +// "", +// datas_array_options.columns, +// [], +// datas_array_options, +// ); +// }, +// Error, +// "Table has no data", +// ); +// }); + +// test("Number col and columns", () => { +// const samples = new CFWF({ +// title: title, +// comment: comment, +// }); +// +// assertThrows( +// () => { +// samples.addArray( +// "number", +// "test numbers", +// "", +// ["one columns"], +// datas_array, +// datas_array_options, +// ); +// }, +// Error, +// "They have 5 columns and 1 renamed columns", +// ); +// }); + +// test("Aligns provided", () => { +// const samples = new CFWF({ +// title: title, +// comment: comment, +// }); +// +// const newoptions = structuredClone(datas_array_options); +// newoptions.aligns = ["onealign"]; +// assertThrows( +// () => { +// samples.addArray( +// "number", +// "test numbers", +// "", +// datas_array_options.columns, +// datas_array, +// newoptions, +// ); +// }, +// Error, +// "They have 5 columns and 1 aligns", +// ); +// +// delete newoptions.aligns; +// assertThrows( +// () => { +// samples.addArray( +// "number", +// "test numbers", +// "", +// datas_array_options.columns, +// datas_array, +// newoptions, +// ); +// }, +// Error, +// "No aligns metadatas found", +// ); +// }); test("Number & array", async () => { - const options: writerOptions = { - charseparator: "┈", + const options: CFWFOptions = { chartabletop: "━", chartablemiddle: "─", chartablebottom: "━", }; const samples = new CFWF({ - title: title, - comment: comment, + dataset: { + title: title, + description: comment, + }, }); - samples.addArray( - "number", - "test numbers", - "", - datas_array_options.columns, - datas_array, - datas_array_options, - ); - - const content = await samples.toCFWF({}); - const lines = content.split("\n"); - const beginheadermarker = searchMarker(lines, options.chartabletop || ""); - - assertEquals( - "Id larger column right center left ", - lines[beginheadermarker + 1], - ); - assertEquals( - "── ───────────── ───── ───────── ─────", - lines[beginheadermarker + 2], - ); - assertEquals( - " 3 12.430 333 33333 333 ", - lines[beginheadermarker + 5], - ); -}); + samples.addTable("number", { + subtitle: "test numbers", + description: "This test is used to check the alignment of numbers", + columns: datas_array_options.columns, + rows: datas_array, + metadatas: { + aligns: datas_array_options.aligns, + }, + }); -test("Number & dict", async () => { - const options: writerOptions = { - charseparator: "┈", - chartabletop: "━", - chartablemiddle: "─", - chartablebottom: "━", - }; + const formated = await samples.outputCFWF(false); + const lines = formated.content.split("\n"); - const samples = new CFWF({ - title: title, - comment: comment, - }); + const titlemarkerpos = searchMarker(lines, chartitlesep || ""); + const descmarkerpos = searchMarker(lines, chardescsep || ""); + const yamlmarkerpos = searchMarker(lines, charyamlsep || ""); - samples.addArray( - "number", - "test numbers", - "", - datas_dict_options.columns, - datas_dict, - datas_dict_options, - ); + assertEquals(8, titlemarkerpos); + assertEquals(10, descmarkerpos); + assertEquals(27, yamlmarkerpos); - const content = await samples.toCFWF({}); - const lines = content.split("\n"); const beginheadermarker = searchMarker(lines, options.chartabletop || ""); assertEquals( @@ -407,27 +429,69 @@ test("Number & dict", async () => { ); }); -test("Feature yaml infos order", async () => { - const samples = new CFWF({}); - - const content = await samples.toCFWF({}); - const lines = content.split("\n"); - - // deno-lint-ignore no-explicit-any - const dsinfos: any = modyaml.parse(lines.join("\n")); - const keys = Object.keys(dsinfos._infos_); - assertEquals(keys, [ - "generated_with", - "removetitlelines", - ]); -}); - -test("Feature (no key element can be found in the doc with marker", () => { - const content = Deno.readTextFileSync("samples.cfwf"); +// test("Number & dict", async () => { +// const options: writerOptions = { +// charseparator: "┈", +// chartabletop: "━", +// chartablemiddle: "─", +// chartablebottom: "━", +// }; +// +// const samples = new CFWF({ +// title: title, +// comment: comment, +// }); +// +// samples.setTable( +// "number", +// { +// subtitle: "test numbers", +// comment: "", +// columns: datas_dict_options.columns, +// rows: datas_dict, +// metadatas: datas_dict_options.metadatas, +// }, +// ); +// +// const content = await samples.outputCFWF({}); +// const lines = content.split("\n"); +// const beginheadermarker = searchMarker(lines, options.chartabletop || ""); +// +// assertEquals( +// "Id larger column right center left ", +// lines[beginheadermarker + 1], +// ); +// assertEquals( +// "── ───────────── ───── ───────── ─────", +// lines[beginheadermarker + 2], +// ); +// assertEquals( +// " 3 12.430 333 33333 333 ", +// lines[beginheadermarker + 5], +// ); +// }); + +// test("Feature yaml infos order", async () => { +// const samples = new CFWF({}); +// +// const content = await samples.outputCFWF({}); +// const lines = content.split("\n"); +// +// // deno-lint-ignore no-explicit-any +// const dsinfos: any = modyaml.parse(lines.join("\n")); +// const keys = Object.keys(dsinfos.dataset); +// assertEquals([ +// "generated_with", +// "removetitlelines", +// ], keys); +// }); + +test("Feature (no key element can be found in the doc with marker", async () => { + const content = await readTextCFWFFile("samples/sample.cfwf"); const lines = content.split("\n"); let idx = 0; - while (lines[idx].indexOf("_infos_:") < 0) { + while (lines[idx].indexOf("dataset:") < 0) { idx++; } @@ -435,23 +499,22 @@ test("Feature (no key element can be found in the doc with marker", () => { // deno-lint-ignore no-explicit-any const pyaml = modyaml.parse(syaml.join("\n")) as any; - const beforekeys = Object.keys(pyaml._infos_); + const beforekeys = Object.keys(pyaml.dataset); // Remove keys can be found in the document with the marker - delete pyaml._infos_.comment; + delete pyaml.dataset.comment; - const afterkeys = Object.keys(pyaml._infos_); + const afterkeys = Object.keys(pyaml.dataset); assertEquals(afterkeys, beforekeys); }); -test("Reader", async () => { +test("Reader & regenerate", async () => { const samples = new CFWF({}); - const content = Deno.readTextFileSync("samples.cfwf"); + const content = await readTextCFWFFile("samples/sample.cfwf"); - samples.fromCFWF(content, {}); - const generatedcontent = await samples.toCFWF(); - Deno.writeTextFileSync("samples_regenerated.cfwf", generatedcontent); + samples.importCFWF(content); + await samples.saveCFWF("samples/samples_regenerated.cfwf", false); - const newcontent = Deno.readTextFileSync("samples_regenerated.cfwf"); + const newcontent = await readTextCFWFFile("samples/samples_regenerated.cfwf"); assertEquals(newcontent, content); }); diff --git a/src/converter.ts b/src/converter.ts new file mode 100644 index 0000000..df7d8f9 --- /dev/null +++ b/src/converter.ts @@ -0,0 +1,67 @@ +import { NamedArray } from "./types.ts"; +import * as modcsv from "https://deno.land/std@0.204.0/csv/mod.ts"; +import { CHARMARKERS, readTextFile } from "./utils.ts"; +import { existsSync } from "https://deno.land/std@0.205.0/fs/exists.ts"; +import { CFWF } from "./cfwf.ts"; + +/////////////////////////////////////////////////////////////////////////////// +// CSV +// ///////////////////////////////////////////////////////////////////////////// +export async function readCSVFile(filename: string): Promise { + const content = await readTextCSVFile(filename); + return getCSVObject(content); +} + +export async function readTextCSVFile(filename: string): Promise { + return await readTextFile(filename); +} + +export function getCSVObject(content: string): NamedArray { + let csv: NamedArray = { + columns: [], + rows: [], + }; + const lines = modcsv.parse(content); + + csv = { + columns: lines[0], + rows: lines.slice(1), + }; + + return csv; +} + +/////////////////////////////////////////////////////////////////////////////// +// CFWF +// ///////////////////////////////////////////////////////////////////////////// +export async function readCFWFFile(filename: string): Promise { + const content = await readTextCFWFFile(filename); + return getCFWFObject(content); +} + +export async function readTextCFWFFile(filename: string): Promise { + const charyamlsep = CHARMARKERS.charyamlsep ?? "╌"; + + const metaname = filename.replace(".cfwf", ".yaml"); + if (existsSync(metaname) === true) { + const content = await readTextFile(filename); + let metadatas = await readTextFile(metaname); + + // replace first --- occurence if exists + if (metadatas.indexOf("---") === 0) { + metadatas = metadatas.replace("---", ""); + } + + return `${content}\n${charyamlsep.repeat(3)}${metadatas}`; + } else { + const content = await readTextFile(filename); + + return content; + } +} + +export function getCFWFObject(content: string): CFWF { + const cfwf = new CFWF({}); + cfwf.importCFWF(content); + return cfwf; +} diff --git a/src/table.ts b/src/table.ts deleted file mode 100644 index 7bbc275..0000000 --- a/src/table.ts +++ /dev/null @@ -1,101 +0,0 @@ -export class Table { - tablename: string; - subtitle: string; - comment: string; - columns: string[]; - // aligns: string[]; - // deno-lint-ignore no-explicit-any - rows: any[]; - // metas, customised fields and also some value cannot be computer from - // fulltext document - // deno-lint-ignore no-explicit-any - metas: any; - - constructor( - tablename: string, - subtitle: string, - comment: string, - columns: string[], - // aligns: string[], - // deno-lint-ignore no-explicit-any - rows: any[], - // deno-lint-ignore no-explicit-any - metas: any, - ) { - if (rows.length == 0) throw new Error("Table has no data"); - - let nbcols = 0; - const isarray = rows[0] instanceof Array; - let keys: string[]; - - if (isarray) { - nbcols = rows[0].length; - keys = columns; - } else { - // Get headers information from row content - keys = Object.keys(rows[0]); - nbcols = keys.length; - - if (columns.length == 0) columns = keys; - - // convert arraykey to array - for (let rdx = 0; rdx < rows.length; rdx++) { - rows[rdx] = Object.values(rows[rdx]); - } - } - - if (nbcols > 0 && (nbcols != columns.length)) { - throw new Error( - `They have ${nbcols} columns and ${columns.length} renamed columns`, - ); - } - - if (!metas.aligns) { - throw new Error( - `No aligns metadatas found`, - ); - } - - if (nbcols != metas.aligns.length) { - throw new Error( - `They have ${nbcols} columns and ${metas.aligns.length} aligns`, - ); - } - - // let objrows = rows; - // if (!isarray) { - // if (keys != columns) { - // for (let rdx = 0; rdx < rows.length; rdx++) { - // const row = rows[rdx]; - // for (let kdx = 0; kdx < keys.length; kdx++) { - // if (keys[kdx] != columns[kdx]) { - // row[columns[kdx]] = row[keys[kdx]]; - // delete row[keys[kdx]]; - // } - // // console.log(`${keys[kdx]} => ${columns[kdx]}`); - // } - // } - // } - // } - - // objrows = []; - // for (let ridx = 0; ridx < rows.length; ridx++) { - // // deno-lint-ignore no-explicit-any - // const fields: any = {}; - // const cols = rows[ridx]; - // for (let cidx = 0; cidx < cols.length; cidx++) { - // // item[headers[cidx]["name"]] = rows[ridx][cidx]; - // fields[keys[cidx]] = cols[cidx]; - // } - // objrows.push(fields); - // } - - this.tablename = tablename; - this.subtitle = subtitle; - this.comment = comment; - // this.aligns = aligns; - this.columns = columns; - this.rows = rows; - this.metas = metas; - } -} diff --git a/src/types.ts b/src/types.ts index f07eda0..7b27512 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,27 +1,82 @@ export type Align = "left" | "center" | "right"; -export type ParsedCSV = { +export type FormatCFWF = { + content: string; + metadatas: string; +}; + +export type NamedArray = { columns: string[]; // deno-lint-ignore no-explicit-any - values: any[]; + rows: any[]; }; -export type readerOptions = { - charseparator?: string; - chartabletop?: string; - chartablemiddle?: string; - chartablebottom?: string; - maxmarkerlines?: number; -}; +// export type readerOptions = { +// chartitlesep?: string; +// chardescsep?: string; +// chartabletop?: string; +// chartablemiddle?: string; +// chartablebottom?: string; +// charyamlsep?: string; +// maxmarkerlines?: number; +// }; -export type writerOptions = { +export type CFWFOptions = { padding?: number; - charseparator?: string; + chartitlesep?: string; + chardescsep?: string; chartabletop?: string; chartablemiddle?: string; chartablebottom?: string; + charyamlsep?: string; removetitleline?: number; // deno-lint-ignore no-explicit-any metas?: any; font?: string; + separate?: boolean; +}; + +export type DatasetType = { + title?: string; + generatedtitle?: string; + description?: string; + tables?: Record; + metadatas?: { + orders?: string[]; + font?: string; + removetitlelines?: number; + sources?: string[]; + license?: string; + author?: string; + version?: string; + // deno-lint-ignore no-explicit-any + [key: string]: any; + }; +}; + +export type TableType = { + subtitle?: string; + description?: string; + columns?: string[]; + // deno-lint-ignore no-explicit-any + rows?: any[]; + metadatas?: { + aligns?: string[]; + sources?: string[]; + license?: string; + author?: string; + // deno-lint-ignore no-explicit-any + [key: string]: any; + }; +}; + +export type ExportTable = { + columns: string[]; + // deno-lint-ignore no-explicit-any + rows: any[]; +}; + +export type CFWFDataset = { + dataset?: DatasetType; + tables?: Record; }; diff --git a/src/utils.ts b/src/utils.ts index f5d6212..932997e 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,19 +1,34 @@ -import { Align, ParsedCSV } from "./types.ts"; -import * as modcsv from "https://deno.land/std@0.204.0/csv/mod.ts"; - -export function parseCSV(content: string): ParsedCSV { - let csv: ParsedCSV = { - columns: [], - values: [], - }; - const lines = modcsv.parse(content); - - csv = { - columns: lines[0], - values: lines.slice(1), - }; - - return csv; +import { CFWF } from "./cfwf.ts"; +import { Align, CFWFOptions } from "./types.ts"; + +export const CHARMARKERS: CFWFOptions = { + padding: 3, + chartitlesep: "┈", + chardescsep: "┄", + chartabletop: "━", + chartablemiddle: "─", + chartablebottom: "━", + charyamlsep: "╌", +}; + +export async function readTextFile(filename: string): Promise { + const r = /https?\:\/\//; + + let content = ""; + if (r.test(filename)) { + const resp = await fetch(filename); + content = await resp.text(); + } else { + content = await Deno.readTextFile(filename); + } + + return content; +} + +export function getCFWFObject(content: string): CFWF { + const cfwf = new CFWF({}); + cfwf.importCFWF(content); + return cfwf; } export function max(a: number, b: number): number { diff --git a/src/utils_test.ts b/src/utils_test.ts index e612a89..1276315 100644 --- a/src/utils_test.ts +++ b/src/utils_test.ts @@ -1,7 +1,7 @@ // mod_test.ts import { assertEquals } from "../test_deps.ts"; +import { getCSVObject } from "./converter.ts"; import { align, max } from "./utils.ts"; -import { parseCSV } from "./utils.ts"; const { test } = Deno; @@ -21,11 +21,11 @@ test("Test align", () => { assertEquals(align("right", "right", 10), " right"); }); -test("parseCSV", () => { - const players_txt = Deno.readTextFileSync("samples/players.csv"); - const players = parseCSV(players_txt); +test("getCSVObject", () => { + const players_txt = Deno.readTextFileSync("samples/initdatas/players.csv"); + const players = getCSVObject(players_txt); - assertEquals(10, players.values.length); + assertEquals(10, players.rows.length); assertEquals(players.columns, [ "winner_ioc", "name_first",