Skip to content
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

Make spear to be changeable the api client via plugin parameter. #189

Merged
merged 3 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions packages/spear-cli/src/browser/InMemoryMagic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@ export default async function inMemoryMagic(
const logger = new SpearLog(settings.quiteMode);
settings.targetPagesPathList = settings.targetPagesPathList || [];

const jsGenerator = new SpearlyJSGenerator(
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

レビュー用コメント: InMemoryMagic はブラウザ上で Spear を動かすために作成しましたが、 Web Containers をサポートしたことにより不要になります。(#187 のバグで今後削除予定)
Comments for Review: InMemoryMagic enable running Spear on browser, however this feature might to be unnecessary due to Web Containers (We can drop this feature on #187)

settings.spearlyAuthKey,
settings.apiDomain,
settings.analysysDomain || "analytics.spearly.com",
);
let state: State = {
pagesList: [],
componentsList: [],
Expand All @@ -36,6 +31,11 @@ export default async function inMemoryMagic(
out: {
assetsFiles: [],
},
jsGenerator: new SpearlyJSGenerator(
settings.spearlyAuthKey,
settings.apiDomain,
settings.analysysDomain || "analytics.spearly.com",
)
};

// If directory has the same name, it will be removed.
Expand Down Expand Up @@ -114,7 +114,7 @@ export default async function inMemoryMagic(
const parsedNode = (await parseElements(
state,
component.node.childNodes as Element[],
jsGenerator,
state.jsGenerator,
settings
)) as Element[];
componentsList.push({
Expand All @@ -132,7 +132,7 @@ export default async function inMemoryMagic(
page.node.childNodes = await parseElements(
state,
page.node.childNodes as Element[],
jsGenerator,
state.jsGenerator,
settings
);
}
Expand Down Expand Up @@ -167,7 +167,7 @@ export default async function inMemoryMagic(
}

// generate static routing files.
state.pagesList = await generateAliasPagesFromPagesList(state, jsGenerator, settings);
state.pagesList = await generateAliasPagesFromPagesList(state, state.jsGenerator, settings);

// Embed assets
const asettsUrlAndRaw: {[key: string]: string} = {};
Expand Down
2 changes: 2 additions & 0 deletions packages/spear-cli/src/interfaces/HookCallbackInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { DefaultSettings } from "./SettingsInterfaces"
import { HTMLElement } from "node-html-parser"
import { FileUtil } from "../utils/file"
import { SpearLog } from "../utils/log"
import { SpearlyJSGenerator } from "@spearly/cms-js-core"

export type SpearSettings = DefaultSettings

Expand All @@ -28,6 +29,7 @@ export interface SpearState {
out: {
assetsFiles: AssetFile[]
}
jsGenerator: SpearlyJSGenerator
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

レビュー用コメント: SpearState はプラグインの各関数の引数として渡されます。 プラグイン実装
Comments for Review: This SpearState will be passed via plugin function. Implementation of plugin


export interface SpearOption {
Expand Down
2 changes: 2 additions & 0 deletions packages/spear-cli/src/interfaces/MagicInterfaces.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { SpearlyJSGenerator } from "@spearly/cms-js-core"
import { HTMLElement } from "node-html-parser"

export type Element = HTMLElement & { props: { [key: string]: string } }
Expand All @@ -23,6 +24,7 @@ export interface State {
out: {
assetsFiles: AssetFile[]
}
jsGenerator: SpearlyJSGenerator
}

export interface SiteMapURL {
Expand Down
13 changes: 6 additions & 7 deletions packages/spear-cli/src/magic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ const fileUtil = new FileUtil(new LocalFileManipulator(), logger)

let dirname = process.cwd()
let Settings: DefaultSettings
let jsGenerator: SpearlyJSGenerator

function initializeArgument(args: Args) {
if (args.src) {
Expand Down Expand Up @@ -59,9 +58,9 @@ async function bundle(): Promise<boolean> {
out: {
assetsFiles: [],
},
}

jsGenerator = new SpearlyJSGenerator(Settings.spearlyAuthKey, Settings.apiDomain, Settings.analysysDomain)
jsGenerator: new SpearlyJSGenerator(Settings.spearlyAuthKey, Settings.apiDomain, Settings.analysysDomain)
}

// Hook API: beforeBuild
for (const plugin of Settings.plugins) {
Expand Down Expand Up @@ -105,7 +104,7 @@ async function bundle(): Promise<boolean> {
// Due to support nested components.
const componentsList = [] as Component[]
for (const component of state.componentsList) {
const parsedNode = await parseElements(state, component.node.childNodes as Element[], jsGenerator, Settings) as Element[]
const parsedNode = await parseElements(state, component.node.childNodes as Element[], state.jsGenerator, Settings) as Element[]
componentsList.push({
"fname": component.fname,
"rawData": parsedNode[0].outerHTML,
Expand All @@ -118,13 +117,13 @@ async function bundle(): Promise<boolean> {

// Run list again to parse children of the pages
for (const page of state.pagesList) {
page.node.childNodes = await parseElements(state, page.node.childNodes as Element[], jsGenerator, Settings)
page.node.childNodes = await parseElements(state, page.node.childNodes as Element[], state.jsGenerator, Settings)
// We need to parseElement twice due to embed nested component.
page.node.childNodes = await parseElements(state, page.node.childNodes as Element[], jsGenerator, Settings)
page.node.childNodes = await parseElements(state, page.node.childNodes as Element[], state.jsGenerator, Settings)
}

// generate static routing files.
state.pagesList = await generateAliasPagesFromPagesList(state, jsGenerator, Settings)
state.pagesList = await generateAliasPagesFromPagesList(state, state.jsGenerator, Settings)

// Hook API: afterBuild
for (const plugin of Settings.plugins) {
Expand Down
3 changes: 2 additions & 1 deletion packages/spear-cli/src/utils/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export function stateDeepCopy(state: State): State {
globalProps: JSON.parse(JSON.stringify(state.globalProps)),
out: {
assetsFiles: assetsDeepCopy(state.out.assetsFiles)
}
},
jsGenerator: state.jsGenerator,
}
}

Expand Down
57 changes: 39 additions & 18 deletions packages/spearly-cms-js-core/src/Generator.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,69 @@
import { HTMLElement, Node, parse } from 'node-html-parser';
import { FieldTypeTags, SpearlyApiClient } from '@spearly/sdk-js';
import getFieldsValuesDefinitions, { generateGetParamsFromAPIOptions, getCustomDateString, ReplaceDefinition } from './Utils.js'
import type { AnalyticsPostParams, Content } from '@spearly/sdk-js'
import type { AnalyticsPostParams, Content, List } from '@spearly/sdk-js'

/**
* FakeSpearlyApiClient is a fake implementation of SpearlyApiClient.
* We can inject api client for using local file system, like markdown files.
*/
export interface FakeSpearlyApiClient {
analytics: {
pageView: (params: any) => Promise<void>;
};
getList(contentTypeId: string, params?: any): Promise<List>;
getContent(contentTypeId: string, contentId: string, params?: any): Promise<Content>;
getContentPreview(contentTypeId: string, contentId: string, previewToken: string): Promise<Content>;
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

レビュー用コメント: 他にも フォーム関係などの関数もありますが、Spear ではフォームを利用しないので定義から外しています。
Comments for Review: sdk-js has form realted function, however Spear doesn't use form API. So I don't defined these function.


export type DateFormatter = (date: Date, dateOnly?: boolean) => string

export type SpearlyJSGeneratorOption = {
linkBaseUrl: string | undefined;
dateFormatter: DateFormatter | undefined;
}
type SpearlyJSGeneratorInternalOption = {
linkBaseUrl: string;
dateFormatter: DateFormatter;
}

export type GetContentOption = {
patternName: string,
previewToken?: string,
}

export type GeneratedContent = {
alias : string,
generatedHtml: string,
tag: string[],
}

export type GeneratedListContent = {
generatedHtml: string,
tag: string
}

export type APIOption = Map<string, string | Date | number | string[] | { [key: string]: string | string[] } >

type SpearlyJSGeneratorInternalOption = {
linkBaseUrl: string;
dateFormatter: DateFormatter;
}

export class SpearlyJSGenerator {
client: SpearlyApiClient
client: SpearlyApiClient | FakeSpearlyApiClient
options: SpearlyJSGeneratorInternalOption

constructor(apiKey: string, domain: string, analyticsDomain: string, options: SpearlyJSGeneratorOption | undefined = undefined) {
this.client = new SpearlyApiClient(apiKey, domain, analyticsDomain)
this.options = {
linkBaseUrl: options?.linkBaseUrl || "",
dateFormatter: options?.dateFormatter || function japaneseDateFormatter(date: Date, dateOnly?: boolean) {
dateFormatter: options?.dateFormatter || function japaneseDateFormatter(date: Date, dateOnly?: boolean) {
return getCustomDateString(`YYYY年MM月DD日${!dateOnly ? " hh時mm分ss秒" : ""}`, date)
}
}
}

injectFakeApiClient(fakeClient: FakeSpearlyApiClient) {
this.client = fakeClient;
}

convertFromFieldsValueDefinitions(templateHtml: string, replacementArray: ReplaceDefinition[], content: Content, contentType: string): string {
let result = templateHtml
replacementArray.forEach(r => {
Expand All @@ -60,7 +81,7 @@ export class SpearlyJSGenerator {

const linkMatchResult = result.match(`{%= ${contentType}_#link %}`)
if (!!linkMatchResult && linkMatchResult.length > 0) {
result = result.split(linkMatchResult[0]).join("./" + this.options.linkBaseUrl + "?contentId=" + alias);
result = result.split(linkMatchResult[0]).join("./" + this.options.linkBaseUrl + "?contentId=" + alias);
}

const aliasMatchResult = result.match(`{%= ${contentType}_#alias %}`)
Expand Down Expand Up @@ -91,16 +112,16 @@ export class SpearlyJSGenerator {
return result
}

async generateContent(templateHtml: string, contentType: string, contentId: string, option: GetContentOption, insertDebugInfo: boolean): Promise<[html: string, uid:string, patternName: string | null]> {
async generateContent(templateHtml: string, contentType: string, contentId: string, option: GetContentOption, insertDebugInfo: boolean): Promise<[html: string, uid: string, patternName: string | null]> {
try {
const result = option.previewToken
? await this.client.getContentPreview(contentType, contentId, option.previewToken)
: await this.client.getContent(contentType, contentId,
option.patternName
? {
patternName: option.patternName
}
: {}
? {
patternName: option.patternName
}
: {}
);
const replacementArray = getFieldsValuesDefinitions(result.attributes.fields.data, contentType, 2, true, this.options.dateFormatter, insertDebugInfo);
const uid = result.attributes.publicUid;
Expand Down Expand Up @@ -132,7 +153,7 @@ export class SpearlyJSGenerator {
}
if (node.childNodes.length > 0) {
node.childNodes = await this.traverseInjectionSubLoop(node.childNodes as HTMLElement[], apiOptions, insertDebugInfo)
}
}
resultNode.appendChild(node)
}
return resultNode.childNodes
Expand All @@ -153,7 +174,7 @@ export class SpearlyJSGenerator {
const result = await this.client.getList(contentType, generateGetParamsFromAPIOptions(apiOptions))
let resultHtml = ""
result.data.forEach(c => {
const replacementArray = getFieldsValuesDefinitions(c.attributes.fields.data, variableName || contentType, 2, true, this.options.dateFormatter, insertDebugInfo);
const replacementArray = getFieldsValuesDefinitions(c.attributes.fields.data, variableName || contentType, 2, true, this.options.dateFormatter, insertDebugInfo);
resultHtml += this.convertFromFieldsValueDefinitions(templateHtml, replacementArray, c, contentType)
})

Expand Down Expand Up @@ -190,7 +211,7 @@ export class SpearlyJSGenerator {
})
let resultHtml = ""
targetContents.forEach(c => {
const replacementArray = getFieldsValuesDefinitions(c.attributes.fields.data, variableName || contentType, 2, true, this.options.dateFormatter, insertDebugInfo);
const replacementArray = getFieldsValuesDefinitions(c.attributes.fields.data, variableName || contentType, 2, true, this.options.dateFormatter, insertDebugInfo);
// Special replacement string
replacementArray.push({
definitionString: `{%= ${contentType}_#tag %}`,
Expand All @@ -204,12 +225,12 @@ export class SpearlyJSGenerator {
})
})
return contentsByTag
} catch(e) {
} catch (e) {
return Promise.reject(e)
}
}

async generateEachContentFromList(templateHtml: string, contentType: string, apiOptions: APIOption, tagFieldName: string, insertDebugInfo: boolean) : Promise<GeneratedContent[]> {
async generateEachContentFromList(templateHtml: string, contentType: string, apiOptions: APIOption, tagFieldName: string, insertDebugInfo: boolean): Promise<GeneratedContent[]> {
try {
const generatedContents: GeneratedContent[] = []
const result = await this.client.getList(contentType, generateGetParamsFromAPIOptions(apiOptions))
Expand Down