-
Notifications
You must be signed in to change notification settings - Fork 6
Jrod/dit 10045 reintroduce pull command with ns cli #116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
017bc22
73dc024
3facdda
5422fe6
ef27c86
35b51f5
e109b1a
a936947
792433e
d5ec804
c1a7269
5756389
eccd1a2
0ddb454
e75b967
d0fa86c
4d82988
eb1eee9
ce9f3fa
faac6c9
2a438e0
a5ac40f
3255e14
eb311d6
4526b44
7f3187b
1f86da5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,8 @@ | ||
| import appContext from "../utils/appContext"; | ||
| import formatOutput from "../formatters"; | ||
|
|
||
| export const pull = async () => { | ||
| console.log("pull"); | ||
| for (const output of appContext.selectedProjectConfigOutputs) { | ||
| await formatOutput(output, appContext.projectConfig); | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import OutputFile from "../shared/fileTypes/OutputFile"; | ||
|
|
||
| export default class BaseFramework { | ||
| protected format: string; | ||
|
|
||
| constructor(format: string) { | ||
| this.format = format; | ||
| } | ||
|
|
||
| process(...args: any[]): OutputFile[] { | ||
| throw new Error("Not implemented"); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| import appContext from "../../utils/appContext"; | ||
| import JavascriptOutputFile from "../shared/fileTypes/JavascriptOutputFile"; | ||
| import OutputFile from "../shared/fileTypes/OutputFile"; | ||
| import { applyMixins } from "../shared"; | ||
| import javascriptCodegenMixin from "../mixins/javascriptCodegenMixin"; | ||
| import JSONOutputFile from "../shared/fileTypes/JSONOutputFile"; | ||
| import BaseFramework from "./base"; | ||
|
|
||
| export default class I18NextFramework extends applyMixins( | ||
| BaseFramework, | ||
| javascriptCodegenMixin | ||
| ) { | ||
| process( | ||
| outputJsonFiles: Record<string, JSONOutputFile<{ variantId: string }>> | ||
| ) { | ||
| const outputDir = appContext.projectConfigDir; | ||
| // Generate Driver file | ||
|
|
||
| const driverFile = new JavascriptOutputFile({ | ||
| filename: "index", | ||
| path: outputDir, | ||
| }); | ||
|
|
||
| const filesGroupedByVariantId = Object.values(outputJsonFiles).reduce( | ||
| (acc, file) => { | ||
| const variantId = file.metadata.variantId; | ||
| acc[variantId] ??= []; | ||
| acc[variantId].push(file); | ||
| return acc; | ||
| }, | ||
| {} as Record<string, OutputFile[]> | ||
| ); | ||
|
|
||
| driverFile.content += this.generateImportStatements(outputJsonFiles); | ||
|
|
||
| driverFile.content += `\n`; | ||
|
|
||
| driverFile.content += this.generateDefaultExportString( | ||
| filesGroupedByVariantId | ||
| ); | ||
|
|
||
| return [driverFile]; | ||
| } | ||
|
|
||
| /** | ||
| * Generates the import statements for the driver file. One import per generated json file. | ||
| * @param outputJsonFiles - The output json files. | ||
| * @returns The import statements, stringified. | ||
| */ | ||
| private generateImportStatements( | ||
| outputJsonFiles: Record<string, JSONOutputFile<{ variantId: string }>> | ||
| ) { | ||
| let importStatements = ""; | ||
| for (const file of Object.values(outputJsonFiles)) { | ||
| importStatements += this.codegenDefaultImport( | ||
| this.sanitizeStringForJSVariableName(file.filename), | ||
| `./${file.filenameWithExtension}` | ||
| ); | ||
| } | ||
| return importStatements; | ||
| } | ||
|
|
||
| /** | ||
| * Generates the default export for the driver file. By default this is an object with the json imports grouped by variant id. | ||
| * @param filesGroupedByVariantId - The files grouped by variant id. | ||
| * @returns The default export, stringified. | ||
| */ | ||
| private generateDefaultExportString( | ||
| filesGroupedByVariantId: Record<string, OutputFile[]> | ||
| ) { | ||
| const variantIds = Object.keys(filesGroupedByVariantId); | ||
|
|
||
| let defaultExportObjectString = "{\n"; | ||
|
|
||
| for (let i = 0; i < variantIds.length; i++) { | ||
| const variantId = variantIds[i]; | ||
| const files = filesGroupedByVariantId[variantId]; | ||
|
|
||
| defaultExportObjectString += `${this.codegenPad(1)}"${variantId}": {\n`; | ||
| for (const file of files) { | ||
| defaultExportObjectString += `${this.codegenPad( | ||
| 2 | ||
| )}...${this.sanitizeStringForJSVariableName(file.filename)},\n`; | ||
| } | ||
| defaultExportObjectString += `${this.codegenPad(1)}}${ | ||
| i < variantIds.length - 1 ? `,\n` : `\n` | ||
| }`; | ||
| } | ||
|
|
||
| defaultExportObjectString += `}`; | ||
|
|
||
| return this.codegenDefaultExport(defaultExportObjectString); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import I18NextFramework from "./i18next"; | ||
|
|
||
| export function getFrameworkProcessor(framework: string) { | ||
| switch (framework) { | ||
| case "i18next": | ||
| return new I18NextFramework(framework); | ||
| default: | ||
| throw new Error(`Unsupported framework: ${framework}`); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import { Output } from "../outputs"; | ||
| import { ProjectConfigYAML } from "../services/projectConfig"; | ||
| import JSONFormatter from "./json"; | ||
|
|
||
| export default function handleOutput( | ||
| output: Output, | ||
| projectConfig: ProjectConfigYAML | ||
| ) { | ||
| switch (output.format) { | ||
| case "json": | ||
| return new JSONFormatter(output, projectConfig).format( | ||
| output, | ||
| projectConfig | ||
| ); | ||
| default: | ||
| throw new Error(`Unsupported output format: ${output}`); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| import fetchText, { PullFilters, TextItemsResponse } from "../http/textItems"; | ||
| import fetchVariables, { Variable, VariablesResponse } from "../http/variables"; | ||
| import BaseFormatter from "./shared/base"; | ||
| import OutputFile from "./shared/fileTypes/OutputFile"; | ||
| import JSONOutputFile from "./shared/fileTypes/JSONOutputFile"; | ||
| import appContext from "../utils/appContext"; | ||
| import { applyMixins } from "./shared"; | ||
| import { getFrameworkProcessor } from "./frameworks"; | ||
|
|
||
| type JSONAPIData = { | ||
| textItems: TextItemsResponse; | ||
| variablesById: Record<string, Variable>; | ||
| }; | ||
|
|
||
| export default class JSONFormatter extends applyMixins( | ||
| BaseFormatter<JSONAPIData>) { | ||
|
|
||
| protected async fetchAPIData() { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: We may have to remove the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. woof possibly. I wrote it this way to make intellisense easier to deal with but we'll need to look into that. |
||
| const filters = this.generatePullFilter(); | ||
| const textItems = await fetchText(filters); | ||
| const variables = await fetchVariables(); | ||
|
|
||
| const variablesById = variables.reduce((acc, variable) => { | ||
| acc[variable.id] = variable; | ||
| return acc; | ||
| }, {} as Record<string, Variable>); | ||
|
|
||
| return { textItems, variablesById }; | ||
| } | ||
|
|
||
| protected async transformAPIData(data: JSONAPIData) { | ||
| const outputDir = appContext.projectConfigDir; | ||
|
|
||
| let outputJsonFiles: Record< | ||
| string, | ||
| JSONOutputFile<{ variantId: string }> | ||
| > = {}; | ||
|
|
||
| const variablesOutputFile = new JSONOutputFile({ | ||
| filename: "variables", | ||
| path: appContext.projectConfigDir, | ||
| }); | ||
|
|
||
| for (let i = 0; i < data.textItems.length; i++) { | ||
| const textItem = data.textItems[i]; | ||
|
|
||
| const fileName = `${textItem.projectId}___${textItem.variantId || "base"}`; | ||
|
|
||
| outputJsonFiles[fileName] ??= new JSONOutputFile({ | ||
| filename: fileName, | ||
| path: outputDir, | ||
| metadata: { variantId: textItem.variantId || "base" }, | ||
| }); | ||
|
|
||
|
|
||
| outputJsonFiles[fileName].content[textItem.id] = textItem.text; | ||
| for (const variableId of textItem.variableIds) { | ||
| const variable = data.variablesById[variableId]; | ||
| variablesOutputFile.content[variableId] = variable.data; | ||
| } | ||
| } | ||
|
|
||
| let results: OutputFile[] = [ | ||
| ...Object.values(outputJsonFiles), | ||
| variablesOutputFile, | ||
| ] | ||
|
|
||
| if (this.output.framework) { | ||
| // process framework | ||
| results.push(...getFrameworkProcessor(this.output.framework).process(outputJsonFiles)); | ||
| } | ||
|
|
||
| return results; | ||
| } | ||
|
|
||
| private generatePullFilter() { | ||
| let filters: PullFilters = { | ||
| projects: this.projectConfig.projects, | ||
| variants: this.projectConfig.variants, | ||
| }; | ||
| if (this.output.projects) { | ||
| filters.projects = this.output.projects; | ||
| } | ||
|
|
||
| if (this.output.variants) { | ||
| filters.variants = this.output.variants; | ||
| } | ||
|
|
||
| return filters; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import { Constructor } from "../shared"; | ||
|
|
||
| interface NamedImport { | ||
| name: string; | ||
| alias?: string; | ||
| } | ||
|
|
||
| export default function javascriptCodegenMixin<TBase extends Constructor>( | ||
| Base: TBase | ||
| ) { | ||
| return class JavascriptCodegenHelpers extends Base { | ||
| protected indentSpaces: number = 2; | ||
|
|
||
| protected sanitizeStringForJSVariableName(str: string) { | ||
| return str.replace(/[^a-zA-Z0-9]/g, "_"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will also replace hyphens with underscores. Do we want to do that? I believe our default delimiter for dev id generation is hyphen, so most dev ids will contain hyphens that are then changed to underscores here.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes they have to be in order for it to be a valid javascript variable name.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm, i wonder why we picked that as our default delimiter then...
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is something totally different, if we were to try to remove all invalid characters from all programming languages we would have no possible string values.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. True, just interesting that we chose to make our default a character that we don't allow and ultimately replace here 🤷♀️ |
||
| } | ||
|
|
||
| protected codegenNamedImport(modules: NamedImport[], moduleName: string) { | ||
| const formattedModules = modules | ||
| .map((m) => { | ||
| if (m.alias) { | ||
| return `${m.name} as ${m.alias}`; | ||
| } | ||
| return m.name; | ||
| }) | ||
| .sort() | ||
| .join(", "); | ||
|
|
||
| return `import { ${formattedModules} } from "${moduleName}";\n`; | ||
| } | ||
|
|
||
| protected codegenDefaultImport(module: string, moduleName: string) { | ||
| return `import ${module} from "${moduleName}";\n`; | ||
jaerod95 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| protected codegenDefaultExport(module: string) { | ||
| return `export default ${module};`; | ||
| } | ||
|
|
||
| protected codegenPad(depth: number) { | ||
| return " ".repeat(depth * this.indentSpaces); | ||
| } | ||
| }; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.