Skip to content

Commit

Permalink
feat: initial coding
Browse files Browse the repository at this point in the history
  • Loading branch information
LastLeaf committed Dec 6, 2024
1 parent 7477204 commit 2038108
Show file tree
Hide file tree
Showing 10 changed files with 447 additions and 12 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,19 @@ npm install 之后,需要点一下小程序开发者工具菜单中的“工

```ts
import { Component } from 'miniprogram-chaining-api-polyfill'
```

然后就可以使用 Chaining API 了。
// 然后就可以使用 Chaining API 了
Component()
// ...
.register()
```

上述方式引入时,会自动判断当前环境是否具有原生的 Chaining API 支持。如果有,就会使用原生的;反之会激活 polyfill 。
注意:如果这个组件本身只用在 glass-easel 组件框架下,最好不要在这个组件文件中引入 polyfill 。

如果需要强制激活 polyfill ,可以这样引入
类似地,也有

```ts
import { ComponentForcePolyfill as Component } from 'miniprogram-chaining-api-polyfill'
import { Behavior } from 'miniprogram-chaining-api-polyfill'
```


Expand Down
11 changes: 9 additions & 2 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,20 @@ const importPlugin = require('eslint-plugin-import')
const prettierRecommended = require('eslint-plugin-prettier/recommended')
const promise = require('eslint-plugin-promise')

module.exports = tseslint.config({
const tsconfig = tseslint.config({
files: ["src/**/*.[jt]s", "dist/**/*.[jt]s"],
extends: [
js.configs.recommended,
importPlugin.flatConfigs.recommended,
promise.configs['flat/recommended'],
prettierRecommended,
tseslint.configs.recommended,
],
rules: {
"@typescript-eslint/no-explicit-any": "off",
},
})

module.exports = [
// importPlugin.flatConfigs.recommended,
...tsconfig,
]
9 changes: 9 additions & 0 deletions package-lock.json

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

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,8 @@
"typescript": "^5.7.2",
"typescript-eslint": "^8.17.0",
"webpack-cli": "^5.1.4"
},
"peerDependencies": {
"miniprogram-api-typings": "^4.0.2"
}
}
288 changes: 288 additions & 0 deletions src/base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
import { type typeUtils } from 'glass-easel'
import { TraitBehavior, TraitGroup } from './trait_behavior'

export type Empty = typeUtils.Empty
export type DataList = WechatMiniprogram.Behavior.DataOption
export type PropertyList = WechatMiniprogram.Behavior.PropertyOption
export type MethodList = WechatMiniprogram.Behavior.MethodOption
export type ChainingFilterType = typeUtils.ChainingFilterType
export type AllData<TData extends DataList, TProperty extends PropertyList> = TData &
WechatMiniprogram.Component.PropertyOptionToData<TProperty>
export type PropertyType = typeUtils.PropertyType
export type PropertyTypeToValueType<T extends PropertyType> = typeUtils.PropertyTypeToValueType<T>
export type ComponentMethod = typeUtils.ComponentMethod
export type TaggedMethod<Fn extends ComponentMethod> = typeUtils.TaggedMethod<Fn>
export type UnTaggedMethod<M extends TaggedMethod<any>> = typeUtils.UnTaggedMethod<M>

type Lifetimes = {
created: () => void
attached: () => void
moved: () => void
detached: () => void
ready: () => void
}

export type GeneralComponent = Component<any, any, any, any>

export type Component<
TData extends DataList,
TProperty extends PropertyList,
TMethod extends MethodList,
TExtraThisFields extends DataList = Empty,
> = WechatMiniprogram.Component.Instance<TData, TProperty, TMethod, []> & TExtraThisFields

export type ResolveBehaviorBuilder<B, TChainingFilter extends ChainingFilterType> =
typeUtils.IsNever<TChainingFilter> extends false
? TChainingFilter extends ChainingFilterType
? Omit<B, TChainingFilter['remove']> & TChainingFilter['add']
: B
: B

class ChainingPolyfillMetadata {
traitGroup = new TraitGroup()
}

const getChainingPolyfillMetadata = (comp: GeneralComponent) => {
return comp._$chainingPolyfill
}

const chainingPolyfillBehavior = Behavior({
created() {
const self = this as any
if (!self._$chainingPolyfill) {
self._$chainingPolyfill = new ChainingPolyfillMetadata()
}
},
})

export class BaseBehaviorBuilder<
TPrevData extends DataList = Empty,
TData extends DataList = Empty,
TProperty extends PropertyList = Empty,
TMethod extends MethodList = Empty,
TChainingFilter extends ChainingFilterType = never,
TPendingChainingFilter extends ChainingFilterType = never,
TComponentExport = never,
TExtraThisFields extends DataList = Empty,
> {
protected _$definition: WechatMiniprogram.Component.Options<any, any, any, any> = {
properties: {},
behaviors: [chainingPolyfillBehavior],
}
private _$export: (() => any) | null = null

/** Add external classes */
externalClasses(list: string[]): this {
const def = this._$definition
if (def.externalClasses) def.externalClasses = def.externalClasses.concat(list)
else def.externalClasses = list
return this
}

/** Set the export value when the component is being selected */
export<TNewComponentExport>(
f: () => TNewComponentExport,
): ResolveBehaviorBuilder<
BaseBehaviorBuilder<
TPrevData,
TData,
TProperty,
TMethod,
TChainingFilter,
TPendingChainingFilter,
TNewComponentExport,
TExtraThisFields
>,
TChainingFilter
> {
if (!this._$definition.export) this._$definition.behaviors.unshift('wx://component-export')
this._$definition.export = f as any
return this as any
}

data<T extends DataList>(
gen: typeUtils.NewFieldList<AllData<TData, TProperty>, T>,
): ResolveBehaviorBuilder<
BaseBehaviorBuilder<
T,
TData & T,
TProperty,
TMethod,
TChainingFilter,
TPendingChainingFilter,
TComponentExport,
TExtraThisFields
>,
TChainingFilter
> {
this._$definition.data(gen)
return this as any
}

property<N extends string, T extends PropertyType, V extends PropertyTypeToValueType<T>>(
name: N,
def: N extends keyof (TData & TProperty) ? never : typeUtils.PropertyListItem<T, V>,
): ResolveBehaviorBuilder<
BaseBehaviorBuilder<
TPrevData,
TData,
TProperty & Record<N, unknown extends V ? T : typeUtils.PropertyOption<T, V>>,
TMethod,
TChainingFilter,
TPendingChainingFilter,
TComponentExport,
TExtraThisFields
>,
TChainingFilter
> {
this._$definition.properties[name] = def
return this as any
}

/**
* Add some public methods
*
* The public method can be used as an event handler, and can be visited in component instance.
*/
methods<T extends MethodList>(
funcs: T & ThisType<Component<TData, TProperty, TMethod, TExtraThisFields>>,
): ResolveBehaviorBuilder<
BaseBehaviorBuilder<
TPrevData,
TData,
TProperty,
TMethod & T,
TChainingFilter,
TPendingChainingFilter,
TComponentExport,
TExtraThisFields
>,
TChainingFilter
> {
Object.assign(this._$definition.methods, funcs)
return this as any
}

/**
* Add a data observer
*/
observer<
P extends typeUtils.ObserverDataPathStrings<AllData<TPrevData, TProperty>>,
V = typeUtils.GetFromObserverPathString<AllData<TPrevData, TProperty>, P>,
>(
paths: P,
func: (this: Component<TData, TProperty, TMethod, TExtraThisFields>, newValue: V) => void,
once?: boolean,
): ResolveBehaviorBuilder<this, TChainingFilter>
observer<
P extends typeUtils.ObserverDataPathStrings<AllData<TPrevData, TProperty>>[],
V = {
[K in keyof P]: typeUtils.GetFromObserverPathString<AllData<TPrevData, TProperty>, P[K]>
},
>(
paths: readonly [...P],
func: (
this: Component<TData, TProperty, TMethod, TExtraThisFields>,
...newValues: V extends any[] ? V : never
) => void,
once?: boolean,
): ResolveBehaviorBuilder<this, TChainingFilter>
observer(
paths: string | readonly string[],
func: (this: Component<TData, TProperty, TMethod, TExtraThisFields>, ...args: any[]) => any,
once = false,
): ResolveBehaviorBuilder<this, TChainingFilter> {
// TODO
return this as any
}

/**
* Add a lifetime callback
*/
lifetime<L extends keyof Lifetimes>(
name: L,
func: (
this: Component<TData, TProperty, TMethod, TExtraThisFields>,
...args: Parameters<Lifetimes[L]>
) => ReturnType<Lifetimes[L]>,
once = false,
): ResolveBehaviorBuilder<this, TChainingFilter> {
// TODO
return this as any
}

/**
* Add a page-lifetime callback
*/
pageLifetime(
name: string,
func: (this: Component<TData, TProperty, TMethod, TExtraThisFields>, ...args: any[]) => any,
once = false,
): ResolveBehaviorBuilder<this, TChainingFilter> {
// TODO
return this as any
}

init<TExport extends Record<string, TaggedMethod<(...args: any[]) => any>> | void>(
func: (
this: Component<TData, TProperty, TMethod, TExtraThisFields>,
builderContext: BuilderContext<
TPrevData,
TProperty,
Component<TData, TProperty, TMethod, TExtraThisFields>
>,
) => TExport,
): ResolveBehaviorBuilder<
BaseBehaviorBuilder<
TPrevData,
TData,
TProperty,
TMethod &
(TExport extends void
? Empty
: {
[K in keyof TExport]: UnTaggedMethod<TExport[K]>
}),
TChainingFilter,
TPendingChainingFilter,
TComponentExport,
TExtraThisFields
>,
TChainingFilter
> {
// TODO
return this as any
}

definition<
TNewData extends DataList = Empty,
TNewProperty extends PropertyList = Empty,
TNewMethod extends MethodList = Empty,
TNewComponentExport = never,
>(
definition: WechatMiniprogram.Component.Options<TNewData, TNewProperty, TNewMethod, any> &
ThisType<
Component<
TData & TNewData,
TProperty & TNewProperty,
TMethod & TNewMethod,
TExtraThisFields
>
>,
): ResolveBehaviorBuilder<
BaseBehaviorBuilder<
TPrevData,
TData & TNewData,
TProperty & TNewProperty,
TMethod & TNewMethod,
TChainingFilter,
TPendingChainingFilter,
TNewComponentExport,
TExtraThisFields
>,
TChainingFilter
> {
// TODO
return this as any
}
}
Loading

0 comments on commit 2038108

Please sign in to comment.